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]);
#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;
}