题目描述
题解
考虑到选出的两个集合的异或值为 0 0 0 ,所以我们可以看做找出集合,其异或值为 0 0 0 ,然后如果这个集合大小是 x x x ,对答案的贡献就是 2 x 2^x 2x
所以我们考虑每个 i i i 对应一个多项式 ( 1 + 2 x a i ) (1+2x^{a_i}) (1+2xai) ,只要我们把多项式乘起来即可
我们考虑 f w t fwt fwt 过程中 i i i 位置上的数对 j j j 位置的贡献是数值乘上 ( − 1 ) p o p c o u n t ( i & j ) (-1)^{popcount(i\And j)} (−1)popcount(i&j) ,不难发现每个多项式 f w t fwt fwt 后数值要么是 − 1 -1 −1 ,要么是 3 3 3
所以我们可以把这些多项式相加后做 f w t fwt fwt ,然后设这个位置有 x x x 个 − 1 -1 −1,那就有 n − x n-x n−x 个 3 3 3 ,解方程即可,然后这一位将变成 ( − 1 ) x 3 n − x (-1)^x3^{n-x} (−1)x3n−x,之后再做 i f w t ifwt ifwt 即可
最后答案因为不能选出空集所以要减一
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1<<20,P=998244353;
const int U=(P+1)>>1,V=748683265;
int n,a[N],w[N];
void fwt(int *a,int o){
for (int i=1;i<N;i<<=1)
for (int j=0;j<N;j+=(i<<1))
for (int x,y,k=0;k<i;k++){
x=a[j+k];y=a[i+j+k];
a[j+k]=(x+y)%P;a[i+j+k]=(x-y+P)%P;
if (o) a[j+k]=1ll*a[j+k]*U%P,
a[i+j+k]=1ll*a[i+j+k]*U%P;
}
}
int main(){
scanf("%d",&n);w[0]=1;
for (int i=1;i<N;i++) w[i]=3ll*w[i-1]%P;
for (int x,i=1;i<=n;i++)
scanf("%d",&x),a[0]++,a[x]+=2;
fwt(a,0);for (int x,i=0;i<N;i++)
x=1ll*(3*n-a[i]+P)*V%P,
a[i]=1ll*((x&1)?P-1:1)*w[n-x]%P;
fwt(a,1);cout<<(a[0]+P-1)%P<<endl;return 0;
}