题意:求出两个集合使他们异或值相同,问方案数
考虑统计那些异或起来为 0 的集合,这样的集合的任何一个划分都是合法的
一个大小为 的集合的贡献是
我们考虑上生成函数然后
得到 过后 回去,第 项的值就是答案
发现如果对每一行都做一遍 太浪费了
能不能对所有的一起做呢?
考虑 的过程, 对所有位置有贡献, 对一些位置有 的贡献,一些有 的贡献,所以最后的值一定是
我们现在需要知道的是一列的变换完后的 ,发现只需要知道其中 -1 和 3 的个数
注意到 的和等于和的 ,将所有的合起来做一遍 就可以解出个数
挺巧妙的,一个是直接写出一个
形式的生成函数
二个是把所有的合起来做一个
,而不是一个一个做
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 1e6 + 5, M = 1 << 21 | 5;
cs int Mod = 998244353, inv2 = (Mod+1)/2;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Mul(int &a, int b){ a = mul(a, b); }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans;}
cs int inv4 = mul(inv2, inv2);
int n, a[M], pw[N], MAX, deg;
void FWT(int *a, int typ){
for(int i = 1; i < deg; i <<= 1)
for(int j = 0; j < deg; j += (i<<1))
for(int k = 0; k < i; k++){
int x = a[k + j], y = a[k + j + i];
a[k + j] = add(x, y); a[k + j + i] = dec(x, y);
if(typ == -1) Mul(a[k + j], inv2), Mul(a[k + j + i], inv2);
}
}
int main(){
scanf("%d", &n); a[0] = n;
for(int i = 1; i <= n; i++){ int x; scanf("%d", &x); MAX = max(MAX, x); a[x] += 2; }
pw[0] = 1; for(int i = 1; i <= n; i++) pw[i] = mul(pw[i-1], 3);
deg = 1; while(deg <= MAX) deg <<= 1;
FWT(a, 1);
for(int i = 0; i < deg; i++){
int ct3 = mul(add(a[i], n), inv4), ct1 = n - ct3;
a[i] = (ct1&1) ? dec(0,pw[ct3]) : pw[ct3];
}
FWT(a, -1); cout << dec(a[0], 1); return 0;
}