神仙題啊...ios
UOJ #310數組
將原集合劃分紅$ A,B,C$三部分,要求知足$ A,B$不全爲空且$ A$的異或和等於$ B$的異或和優化
求方案數spa
集合大小 $n\leq 10^6$ 值域$val \leq 10^6$code
若是要知足$ A,B$的異或和相同,必然有$ A \cup B$中全部元素異或和爲$ 0$blog
若是存在這樣一個集合$ A \cup B$,這之中的每一個元素能夠在集合$ A$中也能夠在集合$ B$中get
即對答案產生$ 2^{|A|+|B|}$的貢獻string
設每一個元素$ a_i$的多項式爲$ 2x^{a_i}+1$it
則答案至關於全部多項式的異或卷積結果的常數項的值減一(減去A,B全爲空的狀況)io
用$ FWT$優化這個卷積,複雜度是$ O(n·val·\log val)$
並得不了什麼分
打表發現這類多項式的$ FWT$結果只有$ -1$和$ 3$兩種數
$ FWT$有一個性質是$ FWT$的和等於和的$ FWT$
所以咱們先對全部多項式求和,再作一次$ FWT$
這時候的$ FWT$結果能夠被$ (-1)x+3(n-x)$表示
這樣能夠求出原先這個位置中$ -1$和$ 3$的數量
就能求出原先數組的$ FWT$以後的對應位乘積的值了
獲得$ FWT$數組後$ O(n)$計算答案便可
時間複雜度$ O(n \log n)$
有過一些惡意卡常
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<vector> #define p 998244353 #define file(x)freopen(x".in","r",stdin);freopen(x".out","w",stdout) #define rt register int #define ll long long #include<sys/mman.h> using namespace std; struct ano{ char*s; ano():s((char*)mmap(0,1<<24,1,2,0,0)){} operator int(){ int x=0; while(*s<48)++s; while(*s>32) x=x*10+*s++-48; return x; } }buf; int k,m,n,x,y,z,cnt,ans,invn; int ksm(int x,int y=p-2){ int ans=1; for(rt i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*ans*x%p; return ans; } int A[1048577]; int mi[1000010],fla[1048576]; int main(){ n=buf;int lim=1,mc=0; for(rt i=1;i<=n;i++)x=buf,A[0]++,A[x]+=2,mc=max(mc,x); while(lim<=mc)lim<<=1; mi[0]=1;for(rt i=1;i<=n;i++)mi[i]=1ll*mi[i-1]*3%p; for(rt i=1;i<lim;i<<=1) for(rt j=0;j<lim;j+=i<<1) for(rt k=0;k<i;k++){ const int x=A[j+k],y=A[i+j+k]; A[j+k]=x+y;A[i+j+k]=x-y; } int inv4=ksm(4); for(rt i=0;i<lim;i++){ x=(3ll*n-A[i])*inv4%p; (ans+=mi[n-x]*((x&1)?-1:1))%=p; } ans=1ll*ans*ksm(lim,p-2)%p; cout<<(ans+p-1)%p; return 0; }