【題解】[UOJ 310] UNR#2 黎明前的巧克力【FWT】
阿新 • • 發佈:2020-12-25
題意
將全集 \(S\) 分為 \(S_1,S_2,S_3\),要求 \(S_1,S_2\) 異或和相等且不全為空。求方案數。\(|S|,x\leq 10^6,\forall a\in S\)
題解
問題可轉化為 \(T\subseteq S,T\neq \varnothing\),\(T\) 異或和為 \(0\),\(T\) 中每個元素貢獻 \(2\) 的係數。
\(a_i\in S\) 可以寫作 \(F_i(x)=x^{\varnothing}+2x^{a_i}\) 的集合冪級數,暴力異或卷積顯然複雜度爆炸。
\(F_i(x)\) FWT 後每個位置為 \(-1\) 或 \(3\),我們只用統計每個位置乘了多少 \(3\)
#include<bits/stdc++.h> using namespace std; const int N=21,mod=998244353,inv4=(mod*3ll+1)/4; int a[1<<N],n; int b[1<<N]; int c[1<<N]; int qpow(int x,int y){ int ans=1; while(y){ if(y&1)ans=ans*1ll*x%mod; x=x*1ll*x%mod; y>>=1; } return ans; } void fwt(int *a,int m,int tp){ for(int i=1;i<1<<m;i<<=1){ for(int j=0;j<1<<m;j+=i<<1){ for(int k=0;k<i;k++){ int x=a[j+k],y=a[i+j+k]; // cerr<<". "<<j+k<<" "<<i+j+k<<endl; a[j+k]=x+y;a[i+j+k]=x-y; a[j+k]>=mod&&(a[j+k]-=mod); a[i+j+k]<0&&(a[i+j+k]+=mod); } } } if(tp==-1){ int q=qpow(1<<m,mod-2); for(int i=0;i<1<<m;i++) a[i]=a[i]*1ll*q%mod; } } int main(){ scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",a+i); for(int i=0;i<n;i++)b[0]++,b[a[i]]+=2;//隨意,只要後面解方程改改即可 int m=0; for(int i=0;i<n;i++)while(1<<m<=a[i])m++; // n=1<<m; fwt(b,m,1); for(int i=0;i<1<<m;i++){ int cnt3=(n+b[i])*1ll*inv4%mod,cnt1=n-cnt3; // cerr<<"> "<<b[i]<<" "<<cnt3<<" "<<cnt1<<endl; c[i]=qpow(3,cnt3)*1ll*(cnt1%2?mod-1:1)%mod; } fwt(c,m,-1); cout<<(c[0]-1+mod)%mod<<endl; }