子集卷积
/* 如代码所示 设p(x)表示x二进制拆分后1的个数 题目要求维护的i&j==0 且 i|j=k 实际上就是 就是i|j=k 且p(i)+p(j)=p(k) 很容易理解 然后我们考虑将FMT拆成两维来同时维护这两个要求 把a[i]插入f[p(i)][i]中,b[i]插入g[p(i)][i]中 然后对每个f[0~lim],g[0~lim]做fmt 然后暴力区间合并维护p(i)+p(j)=p(k)这个条件即可 时间复杂度O(2^n*n^2) */ #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define dwn(i,a,b) for(int i=a;i>b=;i--) #define MAXN 1500000 using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); while('0'>ch || ch>'9'){if(ch=='-') f=-1; ch=getchar();} while('0'<=ch && ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return x*f; } typedef long long ll; const int mod=1e9+9; int check(int x){ int res=0; while(x){ if(x&1) res++; x>>=1; } return res; } int n,lim,f[22][MAXN],g[22][MAXN],h[22][MAXN]; void FWT_or(int *a,int opt){ for(int i=1;i<n;i<<=1) for(int j=0,p=(i<<1);j<n;j+=p) rep(k,0,i-1) if(opt==1) a[j+i+k]=(a[j+i+k]+a[j+k])%mod; else a[j+i+k]=(a[j+i+k]+mod-a[j+k])%mod; } main(){ // freopen("my.out","w",stdout); n=read(); lim=n; n=(1<<n); // rep(i,0,n-1) cout<<check(i)<<" ";cout<<endl; rep(i,0,n-1) f[check(i)][i]=read(); rep(i,0,n-1) g[check(i)][i]=read(); rep(i,0,lim) FWT_or(f[i],1),FWT_or(g[i],1); rep(i,0,lim){ rep(j,0,i){ rep(k,0,n-1) h[i][k]=(h[i][k]+(1ll*f[j][k]*g[i-j][k])%mod)%mod; } } rep(i,0,lim) FWT_or(h[i],-1); rep(i,0,n-1) printf("%d ",h[check(i)][i]); return 0; }