视频加载失败

安吉D5-T2

1471 字
7 分钟
安吉D5-T2
原题呈现

题目描述#

给定一个长度为 nn 的环形序列 a1,a2,,ana_1, a_2, \dots, a_n

其中每个位置的值满足:

  • ai=0a_i = 0,表示第 ii 个位置尚未确定;
  • 1ain1 \le a_i \le n,表示第 ii 个位置已经确定为编号 aia_i 的灵魂宝石.

你需要将所有值为 00 的位置填上剩余未出现的数字,使得最终序列成为一个 11nn 的排列.

对于一个非负整数 xx,定义 cnt(x)\operatorname{cnt}(x) 表示 xx 的二进制表示中 11 的个数.

对于最终排列中一对相邻位置上的数字 x,yx, y,如果 cnt(x&y)\operatorname{cnt}(x \mathbin{\&} y)cnt(xy)\operatorname{cnt}(x \mathbin{|} y) 的奇偶性不同,则称这对相邻数字达成了平衡

其中 &\mathbin{\&} 表示按位与,\mathbin{|} 表示按位或.

由于序列是环形的,(an,a1)(a_n, a_1) 也相邻.

如果最终排列中的所有相邻数字对都达成了平衡,则称这个排列符合圆环之理

现在有 qq 次观测修改.每次修改会将某个位置的值改为一个新的值,新的值可以是 00,也可以是 11nn 之间的整数.

请你分别求出初始状态以及每次修改之后,当前序列可以补全为符合圆环之理的排列数量.

两个补全方案不同,当且仅当至少存在一个位置,在两个最终排列中的数字不同.

答案对 998244353998244353 取模.

输入格式#

第一行包含两个整数 n,qn, q,表示圆环长度和观测修改次数.

第二行包含 nn 个整数 a1,a2,,ana_1, a_2, \dots, a_n,表示初始圆环状态.

接下来 qq 行,每行包含两个整数 p,xp, x,表示一次观测修改:将 apa_p 修改为 xx

输出格式#

输出 q+1q+1 行.

第一行输出初始状态下的答案.

接下来第 ii 行输出第 ii 次修改后的答案.

样例#

输入 #1#

6 6
0 0 0 0 0 0
1 1
2 3
3 2
4 5
5 4
6 1

输出 #1#

72
12
4
2
1
1
0

数据范围#

本题采用捆绑评测,对于一个子任务,你必须通过其中的所有测试点才能得到对应分数.

子任务编号分数n,qn, q \le特殊性质
1101010
2151818
31520002000
4152×1052 \times 10^5q=0q=0
5202×1052 \times 10^5保证任意时刻,序列中存在不为 00 的位置
6252×1052 \times 10^5

对于全部数据:

  • 1n2×1051 \le n \le 2 \times 10^5
  • 0q2×1050 \le q \le 2 \times 10^5
  • 0ain0 \le a_i \le n
  • 1pn1 \le p \le n
  • 0xn0 \le x \le n

观察题意中平衡的条件:若两个数,cnt(x&y)+cnt(xy)\operatorname{cnt}(x \mathbin{\&} y) + \operatorname{cnt}(x \mathbin{|} y) 为奇数(根据题意,这里 cnt\operatorname{cnt} 等同于 popcount\operatorname{popcount}),则这两个数平衡.又由于 cnt(x&y)+cnt(xy)=cnt(x)+cnt(y)\operatorname{cnt}(x \mathbin{\&} y) + \operatorname{cnt}(x \mathbin{|} y) = \operatorname{cnt}(x) + \operatorname{cnt}(y),所以题意中平衡的条件转化为:

popcount\operatorname{popcount} 奇偶性不同的两个数相互平衡.

popcount\operatorname{popcount} 结果为奇数的正整数集合为 s1s_1,称其为一类数,结果为偶数的正整数集合是 s2s_2,称其为二类数,则合法序列必须满足:一类数(和 0)和二类数(和 0)交错排列,因此,s1|s_1| 必须等于 s2|s_2|,否则就始终没有合法的方案.

定义 ci,jc_{i,j}i,j{0,1}i,j\in\{0,1\},表示在已知序列中,i[1,n]\forall i \in [1,n] 满足是一类数(若 i=1i=1)或是二类数(若 i=0i=0)、且处于奇数(j=1j=1)或偶数(j=0j=0)位置的正整数的数量.

先遍历整个已知的序列,计算出 ci,jc_{i,j},再判断以下条件是否成立:

  • 没有重复的正整数
  • 不存在 i{0,1}i\in\{0,1\},满足 ci,0c_{i,0}ci,1c_{i,1} 都不为 0.(保证不会有两个 popcount\operatorname{popcount} 奇偶性相同的数,一个在奇数位置上,一个在偶数位置上)

如果存在任意一个条件不成立,无解,输出 0

否则,令 cnt0cnt_0 表示已知序列二类数数量,cnt0=c0,0+c0,1cnt_0=c_{0, 0} + c_{0, 1}.令 cnt1cnt_1 表示已知序列中一类数数量,cnt1=c1,0+c1,1cnt_1=c_{1, 0} + c_{1, 1}

则存在 f1=s1cnt1f_1 = |s_1| - cnt_1 个可以自由分配位置的一类数,存在 f2=s2cnt2f_2 = |s_2| - cnt_2 个可以自由分配位置的二类数,最终结果为 f1!f2!f_1!f_2!

特别的,若所有数字都是 0(cnt1=cnt2=0cnt_1=cnt_2=0),则一类数和二类数可以整体交换位置,答案要乘 2.

当需要修改时,只需要动态维护 cc 数组,再维护每一个数字出现几次(用于检查是否重复)即可.

标程

#include <bits/stdc++.h>
#define group(x) (__builtin_popcountll(x) % 2)
// 该内建函数(__builtin_popcount)可以计算一个数二进制表示中1的数量
using namespace std;
typedef long long ll;
const int N = 2e5 + 100;
const int MOD = 998244353;
int n, q, a[N], fac[N];
int c[2][2];
int cnt1 = 0, cnt0 = 0;
int rep = 0;
map<int, int> used;
// c[i][j] 表示当前序列中0/1类数在偶/奇位置上的一共有多少个.
int calFac(int x) {
if (!fac[x]) {
fac[x] = 1ll * calFac(x - 1) * x % MOD;
}
return fac[x];
}
void solve() {
if (!((c[0][0] == 0 && c[1][1] == 0) || (c[0][1] == 0 && c[1][0] == 0))) {
cout << 0 << endl;
return;
}
int unused0 = cnt0 - (c[0][1] + c[0][0]);
int unused1 = cnt1 - (c[1][1] + c[1][0]);
ll ans = 1ll * calFac(unused0) * calFac(unused1) % MOD;
if (c[0][1] + c[0][0] + c[1][1] + c[1][0] == 0) {
(ans *= 2) %= MOD;
}
cout << ans << endl;
}
int main() {
#ifdef ONLINE_JUDGE
freopen("circle.in", "r", stdin);
freopen("circle.out", "w", stdout);
#endif
cin >> n >> q;
fac[0] = 1;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (used[a[i]] != 0 && a[i] != 0) {
rep++;
}
used[a[i]]++;
if (a[i] != 0)
c[group(a[i])][i % 2]++;
}
for (int i = 1; i <= n; i++) {
if (group(i)) {
cnt1++;
} else {
cnt0++;
}
}
if (cnt1 != cnt0) {
for (int i = 0; i <= q; i++) {
cout << 0 << endl;
}
return 0;
}
if (!rep)
solve();
else
cout << 0 << endl;
for (int i = 1; i <= q; i++) {
int p, x;
cin >> p >> x;
if (a[p]) {
c[group(a[p])][p % 2]--;
used[a[p]]--;
}
if (used[a[p]] == 1) {
rep--;
}
a[p] = x;
if (x) {
c[group(x)][p % 2]++;
used[x]++;
}
if (used[x] == 2) {
rep++;
}
if (rep) {
cout << 0 << endl;
continue;
}
solve();
}
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

安吉D5-T2
https://blog.jerrylab.top/posts/problem/anji2026/D5/T2/
作者
Jerry
发布于
2026-08-06
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Jerry
Hello, I'm Jerry.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
最新动态
站点统计
文章
80
分类
3
标签
35
总字数
89,198
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0