简介:
就是FWT加了一维个数。
例题:
给定长度为$2^n$的多项式a,b,求一个多项式c,使得$c_k = sum limits_{i& j=0,i|j=k}{a_i b_j}$。
$nleq 20$。
题解:
普通的FWT能够解决$c_k = sum limits_{i|j=k}{a_i b_j}$的形式,考虑多的这个$i& j=0$的限制怎么办。
我们给多项式$f_j$增加一维变成$f_{i,j}$,如果状态j中1的个数为i($siz_j =i$)则$f_{i,j}=a_{j}$,否则$f_{i,j}=0$。
然后对于每个$f_i$所代表的多项式做一个子集和(正变换)。
此时$f_{i,S}$代表S的子集中满足$siz_k =i$的子集k的系数之和。(类似地,令$g_{i,S}$代表b)
现在就可以进行卷积了,令$h_i = sum limits_{j=0}^{i}{f_j * g_{i-j} }$。
此时$h_{i,S}=sum limits_{k|jsubseteq S,siz_k + siz_j = i}{a_k b_j}$。
我们再对每个$h_{i}$做一个子集差(逆变换),此时$h_{i,S}=sum limits_{k|j = S,siz_k + siz_j = i}{a_k b_j}$。
那么第S项(状态S)的答案就是$c_{S}=h_{|S|,S}$。
复杂度$O(n^{2}2^{n})$。(为啥洛谷的模板题卡常卡空间啊,我吐了)
代码:
#include<bits/stdc++.h> #define maxn 1048580 #define maxm 21 #define inf 0x7fffffff #define mod 1000000009 #define ll long long #define rint register int #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; ll siz[maxn]; struct poly{ vector<int> a; ll n; inline void clear(){n=0;} inline void fwt(ll op){ for(rint l=2;l<=n;l<<=1) for(rint i=0;i<n;i+=l) for(rint j=i;j<i+l/2;j++) a[j+l/2]=(a[j+l/2]+op*a[j]+mod)%mod; } poly operator+(const poly b)const{ poly res; res.n=max(n,b.n); for(rint i=0;i<res.n;i++){ if(i>=min(n,b.n)) res.a.push_back((n<b.n)?b.a[i]:a[i]); else res.a.push_back((a[i]+b.a[i])%mod); } return res; } poly operator*(const poly b)const{ poly res; res.n=max(n,b.n); for(rint i=0;i<res.n;i++){ if(i>=min(n,b.n)) res.a.push_back(0); else res.a.push_back(((ll)a[i]*(ll)b.a[i])%mod); } return res; } }; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline poly calc(poly A,ll m){ poly T; T.n=A.n; for(rint i=0;i<A.n;i++) T.a.push_back((siz[i]==m)?A.a[i]:0); T.fwt(1); return T; } inline void print(poly A){ printf("%d:",A.n); for(int i=0;i<A.n;i++) printf(" %d",A.a[i]); printf(" "); } int main(){ ll n=read(),m=1<<n; poly A,B; A.clear(),B.clear(),A.n=B.n=m; for(rint i=0;i<m;i++) A.a.push_back(read()); for(rint i=0;i<m;i++) B.a.push_back(read()); for(rint i=0;i<m;i++) for(rint j=0;j<n;j++) siz[i]+=((i>>j)&1); poly RA[maxm],RB[maxm],R[maxm]; for(ll i=0;i<=n;i++) RA[i]=calc(A,i),RB[i]=calc(B,i); for(rint i=0;i<=n;i++){ R[i].n=0; for(rint j=0;j<=i;j++) R[i]=(R[i]+(RA[j]*RB[i-j])); R[i].fwt(-1); } for(rint i=0;i<m;i++) printf("%lld ",R[siz[i]].a[i]); printf(" "); return 0; }