题解 黎明前的巧克力
题目大意
初始有两个数 \(a,b\) ,有 \(n\) 次操作,每次提供一个数 \(a_i\) ,要么不操作,要么从 \(a,b\) 中选一个数异或上 \(a_i\) ,问最后 \(a,b\) 相同的方案数。
\(n,a_i\le 10^6\)
思路
不难看出如果我们设 \(x=a\oplus b\) ,那么每次操作就是 \(x\gets x\oplus a_i\) ,于是我们可以想到使用 \(\texttt{FWT}\) 解决这个问题。我们发现最后的答案其实就是:
\[[x^0]\bigoplus_{i=1}^{n}(1+2x^{a_i})-1
\]
(减 \(1\) 是因为题目要求不能不操作,尽管这显得非常多此一举)
然后我们就发现直接 \(\texttt{FWT}\) 铁定 gg ,然后我们考虑到有值得数位很少,可以联想到 CF1119H Triple ,我们发现 \(\texttt{FWT}[i]\) 要么为 \(-1\) 要么为 \(3\) ,因为 \(1\) 产生的贡献一定为 \(1\) ,而 \(2x^{a_i}\) 产生的贡献一定为 \(\pm 2\) 。
于是,我们的问题就是对于每一位知道有多少个 \(3\) (因为 \(3\) 的个数和 \(-1\) 的个数之和一定为 \(n\))。我们设这个东西为 \(x\) ,我们发现如果设
\[f_i=\texttt{FWT}(\sum_{i=1}^{n}(1+2x^{a_i}))[i]
\]
那我们就有等式:
\[(-x)+3(n-x)=f_i
\]
于是我们就可以解出 \(x\) 了 。然后我们将这个东西带回去,\(\texttt{IDWT}\) 一遍就好了。
时间复杂度 \(\Theta(n\log^2 n)\),假设 \(n\) 与值域同阶。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 998244353
#define MAXN 1048576
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,maxf,inv2,inv4,logn,g[MAXN],aa[MAXN],pw[MAXN];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
return res;
}
void FWT (int *f,int n){
for (Int i = 1;i < n;i <<= 1)
for (Int j = 0;j < n;j += i << 1)
for (Int k = 0;k < i;++ k){
int x = f[j + k],y = f[i + j + k];
f[j + k] = add (x,y),f[i + j + k] = dec (x,y);
}
}
void IFWT (int *f,int n){
for (Int i = 1;i < n;i <<= 1)
for (Int j = 0;j < n;j += i << 1)
for (Int k = 0;k < i;++ k){
int x = f[j + k],y = f[i + j + k];
f[j + k] = mul (inv2,add (x,y)),f[i + j + k] = mul (inv2,dec (x,y));
}
}
signed main(){
read (n),pw[0] = 1;
inv2 = qkpow (2,mod - 2),inv4 = qkpow (4,mod - 2);
for (Int i = 1;i <= n;++ i) pw[i] = mul (pw[i - 1],3);
for (Int i = 1,ai;i <= n;++ i) read (ai),g[0] ++,g[ai] += 2,maxf = max (maxf,ai);
while ((1 << logn) <= maxf) logn ++;
FWT (g,1 << logn);
for (Int i = 0;i < 1 << logn;++ i) {
int x = mul (dec (3 * n,g[i]),inv4);
g[i] = mul (x & 1 ? (mod - 1) : 1,pw[n - x]);
}
IFWT (g,1 << logn);
write (dec (g[0],1)),putchar ('\n');
return 0;
}