1# 正题
题目链接:https://uoj.ac/problem/310
题目大意
给出一个长度为nnn的序列,求有多少种方案找出两个集合S,TS,TS,T使得这两个集合的异或和相等。
1≤n≤1061\leq n\leq 10^61≤n≤106
解题思路
可以转换为找到一个异或和为000的集合SSS,产生2∣S∣2^{|S|}2∣S∣的方案数。
然后考虑FWTFWTFWT,那么我们就是要求∏FWT(1+2xai)\prod FWT(1+2x^{a_i})∏FWT(1+2xai)。
这个东西比较难搞,我们考虑FWT(1+2xai)FWT(1+2x^{a_i})FWT(1+2xai)的性质,FWT(1+2xai)=FWT(1)+FWT(2xai)FWT(1+2x^{a_i})=FWT(1)+FWT(2x^{a_i})FWT(1+2xai)=FWT(1)+FWT(2xai),然后FWT(1)FWT(1)FWT(1)全是111,FWT(2xai)FWT(2x^{a_i})FWT(2xai)的话就有的位置是222有的位置是−2-2−2,那么最后FWT(1+2xai)FWT(1+2x^{a_i})FWT(1+2xai)出来的只会有333和−1-1−1。
那么如果我们求出FWT(∑i=1n1+2xai)FWT(\sum_{i=1}^n1+2x^{a_i})FWT(∑i=1n1+2xai),这样我们就能求出所有FWTFWTFWT的每一位值的和,又因为总数是nnn,我们又知道333和−1-1−1的和,那我们就能解出333和−1-1−1的数量,然后就能求出∏FWT(1+2xai)\prod FWT(1+2x^{a_i})∏FWT(1+2xai),再IFWTIFWTIFWT就好了。
时间复杂度:O(nlogn)O(n\log n)O(nlogn)。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1<<20,P=998244353;
ll n,m,a[N];
void FWT(ll *f,ll op){for(ll p=2;p<=n;p<<=1)for(ll k=0,len=p>>1;k<n;k+=p)for(ll i=k;i<k+len;i++){ll x=f[i],y=f[i+len];f[i]=(x+y)*op%P;f[i+len]=(x-y+P)*op%P;}return;
}
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans;
}
signed main()
{scanf("%lld",&m);n=1<<20;for(ll i=1,x;i<=m;i++)scanf("%lld",&x),a[0]++,a[x]+=2;FWT(a,1);for(ll i=0;i<n;i++){ll _1=0,_3=0;_3=(a[i]+m)*power(4,P-2)%P;_1=m-_3;a[i]=power(3,_3)*((_1&1)?1:(P-1))%P;}FWT(a,(P+1)/2);printf("%lld\n",P-a[0]-1);return 0;
}