这个东西好玄乎呀 首先就是它可以干什么: codeforces 914G 然后你就会说:“这tm什么鬼题!” 好,我们这次就是要解决这个问题,看完这篇你应该就可以掌握FWT 的代码了 我肯定是不会讲的,我们移步这里: http://picks.logdown.com/posts/179290-fast-walsh-hadamard-transform 看完之后应该差不多了 如果要看数学证明可以去这里: http://blog.csdn.net/zhshrs/article/details/54838466
先说上面那个题的做法吧: (sa|sb) ( s a | s b ) & sc s c & (sd ( s d ^ se) s e ) 我们记 ai=∑nj=1[sj=i] a i = ∑ j = 1 n [ s j = i ] ,也就是i在s中的出现次数 然后我们就可以把这三部分分开考虑(以&为分割) 我们计算3个数组A,B,C,分别代表三部分的答案 Ai=fibi∗∑j∑k[j A i = f i b i ∗ ∑ j ∑ k [ j | k=i][j k = i ] [ j & k=0]aj∗ak k = 0 ] a j ∗ a k Bi=fibi∗ai B i = f i b i ∗ a i Ci=fibi∗∑j∑k[j C i = f i b i ∗ ∑ j ∑ k [ j ^ k=i]aj∗ak k = i ] a j ∗ a k 第一部分就是子集卷积,可以直接 3n 3 n ,也可以 n22n n 2 2 n 第二部分直接算 第三部分就是个异或FWT 然后再把A,B,C卷起来就好辣(当然是与卷积辣) 然后枚举每一位算答案就好辣 时间复杂度: O(3n+n2n) O ( 3 n + n 2 n ) 代码在这里:
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<cstdlib> #define LL long long using namespace std; inline int read(){ int x=0,f=1;char ch=' '; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } const LL N=1<<17,mod=1e9+7,inv=5e8+4; inline void FWT_AND(LL *a){ for(int d=1;d<N;d<<=1) for(int i=0;i<N;i+=d<<1) for(int j=0;j<d;++j){ LL x=a[i+j],y=a[i+j+d]; a[i+j]=(x+y)%mod; } } inline void IFWT_AND(LL *a){ for(int d=1;d<N;d<<=1) for(int i=0;i<N;i+=d<<1) for(int j=0;j<d;++j){ LL x=a[i+j],y=a[i+j+d]; a[i+j]=(x-y+mod)%mod; } } inline void FWT_XOR(LL *a){ for(int d=1;d<N;d<<=1) for(int i=0;i<N;i+=d<<1) for(int j=0;j<d;++j){ LL x=a[i+j],y=a[i+j+d]; a[i+j]=(x+y)%mod;a[i+j+d]=(x-y+mod)%mod; } } inline void IFWT_XOR(LL *a){ for(int d=1;d<N;d<<=1) for(int i=0;i<N;i+=d<<1) for(int j=0;j<d;++j){ LL x=a[i+j],y=a[i+j+d]; a[i+j]=(x+y)*inv%mod;a[i+j+d]=(x-y+mod)*inv%mod; } } LL n,A[N],B[N],C[N],a[N],fib[N]; int main(){ fib[1]=1; for(int i=2;i<N;++i)fib[i]=(fib[i-1]+fib[i-2])%mod; n=read(); for(int i=1;i<=n;++i){ int x=read(); a[x]++; } for(int i=0;i<N;++i){ A[i]=0; B[i]=a[i]; C[i]=a[i]; } for(int i=0;i<N;++i){ int t=(N-1)&~i; for(int b=t;;b=(b-1)&t){ A[i|b]=(A[i|b]+a[i]*a[b])%mod; if(!b)break; } } FWT_XOR(C); for(int i=0;i<N;++i)C[i]=C[i]*C[i]%mod; IFWT_XOR(C); for(int i=0;i<N;++i)A[i]=A[i]*fib[i]%mod; for(int i=0;i<N;++i)B[i]=B[i]*fib[i]%mod; for(int i=0;i<N;++i)C[i]=C[i]*fib[i]%mod; FWT_AND(A); FWT_AND(B); FWT_AND(C); for(int i=0;i<N;++i)A[i]=A[i]*B[i]%mod*C[i]%mod; IFWT_AND(A); LL ans=0; for(int i=0;i<17;++i)ans=(ans+A[1<<i])%mod; printf("%I64d",ans); return 0; }然后我要说的就是代码 我们肯定不能用递归版的,常数大概3倍(不要问我怎么知道的,问rqy) 上面那个就是非递归版的 其实就和FFT差不多 而且比FFT好背 然后就没什么了 完结撒花❀
