[UOJ310]黎明前的巧克力
阿新 • • 發佈:2018-07-23
char sin block class 集合 http .html cpp mod
所以按位加,共\(n\)個多項式,最後的值為\(val\),則\(3\)的個數為\(x\),\(3*x+(-1)*(n-x)=val\),可以得到該位上\(3\)的總個數
最後是要乘起來的,所以\(-1\)只是變符號,\((-1)^{n-x}3^x\)就是\(Ans\)的該位的值了,最後\(UFWT\)回來\(Ans[0]-1\)即為答案(多算了全是空集的一種情況)
[UOJ310]黎明前的巧克力
Tags:題解
作業部落
評論地址
TAG:FWT
題意
在集合中選出任意多數,使得異或和為\(0\),再將其分為兩個有區別的可空集合的方案數(兩集合不能都為空)
題解
考慮生成函數
如果選出一個異或和為\(0\)的集合大小為\(k\),那麽對答案的貢獻就是\(2^k\),於是把系數置為\(2\)
假設\(n\)個數的生成函數為\(2x^{a[i]}\),分別為\(A,B,C...\)
那麽答案就是\((A*B)[0],(B*C)[0],(A*B*C)[0]...\)(異或卷積)
我們可以把每個生成函數的\(0\)次項置為\(1\),那麽答案就直接是\((A*B*C...)[0]\)
就應該是\(Ans=FWT(A)*FWT(B)*FWT(C)...\)(每一位對應乘)
然後再把\(Ans\)給\(UFWT\)回來就是答案了
由於\(FWT\)的可加性(證明戳我)
大概就是說\(FWT\)的本質就是高維前綴和,兩個數組先算前綴和再加和先加再算前綴和的效果是一樣的
\(FWT(A+B)=FWT(A)+FWT(B)\)
而且每個多項式都很特殊,\(0\)位上為\(1\)會對每一位做貢獻,\(a[i]\)位為\(2\)會對一些位做\(2\)的貢獻對另一些位做\(-2\)的貢獻(因為是異或卷積所以每一位的數\(FWT\)後都會對所有的位造成影響),由此每一位要麽為\(-1\)要麽為\(3\)
所以按位加,共\(n\)個多項式,最後的值為\(val\),則\(3\)的個數為\(x\),\(3*x+(-1)*(n-x)=val\),可以得到該位上\(3\)的總個數
最後是要乘起來的,所以\(-1\)只是變符號,\((-1)^{n-x}3^x\)就是\(Ans\)的該位的值了,最後\(UFWT\)回來\(Ans[0]-1\)即為答案(多算了全是空集的一種情況)
代碼
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> using namespace std; int read() { char ch=getchar();int h=0,t=1; while((ch>'9'||ch<'0')&&ch!='-') ch=getchar(); if(ch=='-') t=-1,ch=getchar(); while(ch>='0'&&ch<='9') h=h*10+ch-'0',ch=getchar(); return h*t; } const int mod=998244353; const int N=1<<21; const int inv=499122177; int n,A[N],B[N],bit3[N],l; void FWT_xor(int *P,int op) { for(int i=1;i<l;i<<=1) for(int j=0,p=i<<1;j<l;j+=p) for(int k=0;k<i;k++) { int X=P[j+k],Y=P[j+k+i]; P[j+k]=1ll*(X+Y)%mod*op%mod; P[j+k+i]=1ll*((X-Y)%mod+mod)*op%mod; } } int main() { n=read();A[0]=n;bit3[0]=1;int mx=0; for(int i=1;i<=n;i++) bit3[i]=bit3[i-1]*3ll%mod; for(int i=1,x;i<=n;i++) A[x=read()]+=2,mx=max(mx,x); for(l=1;l<=mx;l<<=1); FWT_xor(A,1); for(int i=0;i<l;i++) { int x=(3ll*n-A[i]+mod)*inv%mod*inv%mod; A[i]=bit3[n-x]; if(x&1) A[i]=mod-A[i]; } FWT_xor(A,inv); printf("%d\n",(A[0]-1+mod)%mod); }
[UOJ310]黎明前的巧克力