子集卷积学习笔记

子集卷积学习笔记

\[h_S=\sum_{L\cup R=S,L\cap S=\emptyset} f_Lg_R \]

\[f(i,S)=\sum_{T\in S,|T|=i} f(T) \]

这个对于每个 \(i\) 做一次FMT即可

然后有

\[h(i,S)=\sum_{j=0}^i f(j,S)g(i-j,S) \]

交集为空集,那么元素个数加起来应该等于并集的元素个数

最后直接IFWT即可

其实本质就是按元素个数归类了一下。

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,pos=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
	return pos?x:-x;
} 
#define ll long long
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
#define ROF(i,a,b) for(register int i=(a);i>=(b);--i)
const int mod = 1e9+9;
#define add(a,b) a=a+b>=mod?a+b-mod:a+b
#define del(a,b) a=a<b?a-b+mod:a-b
const int N = 1<<20;
int m,n,f[21][N],g[21][N],h[21][N],bi[N];
void FWT(int *f,int opt){
	for(register int l=2;l<=n;l<<=1){
		int mid=l/2;
		for(int *g=f;g!=f+n;g+=l){
			FOR(i,0,mid-1){
				if(opt==1) add(g[i+mid],g[i]);
				else del(g[i+mid],g[i]);
			}
		}
	}
} 
int main(){
	m=read();n=1<<m;
	FOR(i,0,n-1) bi[i]=bi[i>>1]+(i&1),f[bi[i]][i]=read();
	FOR(i,0,n-1) g[bi[i]][i]=read();
	FOR(i,0,m){
		FWT(f[i],1);FWT(g[i],1);
	}
	FOR(i,0,m){
		FOR(j,0,n-1){
			FOR(k,0,i){
				add(h[i][j],1ll*f[k][j]*g[i-k][j]%mod); 
			}
		}
	}
	FOR(i,0,m){
		FWT(h[i],-1);
	}
	FOR(i,0,n-1){
		printf("%d ",h[bi[i]][i]); 
	}
	return 0;
}
posted @ 2020-05-28 10:18  lcyfrog  阅读(226)  评论(0编辑  收藏  举报