FWT(2):子集卷积

子集卷积:

\[C[k]=\sum_{{i \And j=0},{i|j=k}} A[i] B[j] \]

很明显,i|j=k 的部分很像 FWT。加上限制条件“\(i\And j=0\)”后,等价于 \(c(i|j)=c(i)+c(j)\),因此多加一维记录子集大小(\(c(x)\)

\[h_i=\sum_{k=0}^i A_k[i]*B_{i-k}[j] \]

其中 \(A_k[i]\) 只在 \(c(i)=k\) 时才等于 \(A[i]\),否则等于 \(0\)

\(A_k[i]*B_{i-k}[j]\) 可以使用一次 \(O(n\log n)\) 的 FWT 来求。每次对 \(h_i\) 做 IFFT。答案就是 \(h_{c(i)}[i]\)

for(int i=0;i<=17;i++)fwt(tmp2[i],1);
for(int i=0;i<=17;i++){
	memset(h,0,sizeof h);
  	for(int k=0;k<=i;k++)
  		for(int j=0;j<sz;j++)
  			(h[j]+=1ll*tmp2[k][j]*tmp2[i-k][j]%mod)%=mod;
  	fwtor(h,mod-1);
}
for(int i=0;i<=sz;i++)printf("%d ",h[__builtin_popcount(i)][i]);

练习:Sum the Fibonacci

#include <bits/stdc++.h>
using namespace std;
const int N=(1<<17)+5,kN=1e6+5,mod=1e9+7,I2=(mod+1)/2;
int n,sz,s[kN],t[N],fib[N],f1[N],f2[N],f3[N],tmp[N],tmp2[18][N],h[N];
void fwtor(int *arr,int type){
	for(int w=1;w<sz;w<<=1)
		for(int j=0;j<sz;j+=w<<1)
			for(int i=j;i<j+w;i++)
				(arr[i+w]+=1ll*arr[i]*type%mod)%=mod;
}
void fwtand(int *arr,int type){
	for(int w=1;w<sz;w<<=1)
		for(int j=0;j<sz;j+=w<<1)
			for(int i=j;i<j+w;i++)
				(arr[i]+=1ll*arr[i+w]*type%mod)%=mod;
}
void fwtxor(int *arr,int type){
	for(int w=1;w<sz;w<<=1)
		for(int j=0;j<sz;j+=w<<1)
			for(int i=j;i<j+w;i++){
				int x=(arr[i]+arr[i+w])%mod,y=(arr[i]-arr[i+w]+mod)%mod;
				arr[i]=1ll*x*type%mod,arr[i+w]=1ll*y*type%mod;
			}
}
void print(int *arr){
	for(int i=0;i<sz;i++)printf("%d ",arr[i]); puts("");
}
int main(){
	scanf("%d",&n);
	int mxs=0;
	for(int i=1;i<=n;i++)scanf("%d",&s[i]),t[s[i]]++,mxs=max(mxs,s[i]);
	for(sz=1;sz<=mxs;sz<<=1);
	fib[1]=1;
	for(int i=2;i<sz;i++)fib[i]=(fib[i-1]+fib[i-2])%mod;
	for(int i=1;i<=n;i++)tmp2[__builtin_popcount(s[i])][s[i]]++;
	for(int i=0;i<=17;i++)fwtor(tmp2[i],1);
	for(int i=0;i<=17;i++){
		memset(h,0,sizeof h);
		for(int k=0;k<=i;k++)
			for(int j=0;j<sz;j++)
				(h[j]+=1ll*tmp2[k][j]*tmp2[i-k][j]%mod)%=mod;
		fwtor(h,mod-1);
		for(int j=0;j<sz;j++)if(__builtin_popcount(j)==i)(f1[j]+=h[j])%=mod;
	}
	for(int i=0;i<sz;i++)f1[i]=1ll*f1[i]*fib[i]%mod;
	for(int i=0;i<sz;i++)f2[i]=1ll*t[i]*fib[i]%mod;
	memcpy(tmp,t,sizeof t),fwtxor(tmp,1);
	for(int i=0;i<sz;i++)tmp[i]=1ll*tmp[i]*tmp[i]%mod;
	fwtxor(tmp,I2);
	for(int i=0;i<sz;i++)f3[i]=1ll*fib[i]*tmp[i]%mod;//一定要先做FWT,再做IFWT,最后乘fib,如果在中间乘fib,就会卷出不知道什么东西来
	fwtand(f1,1),fwtand(f2,1),fwtand(f3,1);
	for(int i=0;i<sz;i++)f1[i]=1ll*f1[i]*f2[i]%mod*f3[i]%mod;
	fwtand(f1,mod-1);
	int ans=0;
	for(int i=1;i<sz;i<<=1)(ans+=f1[i])%=mod;
	cout<<ans;
}
posted @ 2022-07-19 16:43  pengyule  阅读(47)  评论(0)    收藏  举报