子集卷积

/*
如代码所示
设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;
}
原文地址:https://www.cnblogs.com/handsome-zlk/p/14359169.html