LOJ#152. 子集卷积
终于 get 到了子集卷积的正确姿势,以前竟然都是用异或卷积写的.
众所周知,异或卷积由于涉及到乘法所以会比较慢,那我们用或卷积就好了!
code:
#include <bits/stdc++.h> #define N (1<<21) #define ll long long #define mod 1000000009 #define lowbit(x) ((x)&(-(x))) #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,inv2,lim; int f[N],g[N],A[21][N],B[21][N],C[21][N],cnt[N]; int qpow(int x,int y) { int tmp=1; for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod; return tmp; } int INV(int x) { return qpow(x,mod-2); } void FWT(int *a) { for(int len=1;len<lim;len<<=1) for(int i=0;i<lim;i+=len<<1) for(int j=0;j<len;++j) (a[i+j+len]+=a[i+j])%=mod; } void IFWT(int *a) { for(int len=1;len<lim;len<<=1) for(int i=0;i<lim;i+=len<<1) for(int j=0;j<len;++j) (a[i+j+len]+=mod-a[i+j])%=mod; } char *p1,*p2,buf[100000]; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int rd() { int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x; } void print(int x) { if(x>=10) print(x/10); putchar(x%10+'0');} int main() { // setIO("input"); n=rd(),lim=1<<n; for(int i=0;i<lim;++i) f[i]=rd(); for(int i=0;i<lim;++i) g[i]=rd(); for(int i=1;i<lim;++i) cnt[i]=cnt[i-lowbit(i)]+1; for(int i=0;i<lim;++i) A[cnt[i]][i]=f[i],B[cnt[i]][i]=g[i]; for(int i=0;i<=n;++i) FWT(A[i]),FWT(B[i]); for(int i=0;i<=n;++i) { for(int j=0;j<=n;++j) if(i+j<=n) { for(int k=0;k<lim;++k) (C[i+j][k]+=(ll)A[i][k]*B[j][k]%mod)%=mod; } } for(int i=0;i<=n;++i) IFWT(C[i]); for(int i=0;i<lim;++i) print(C[cnt[i]][i]),putchar(' '); return 0; }