LOJ#152. 子集卷积
终于 get 到了子集卷积的正确姿势,以前竟然都是用异或卷积写的.
众所周知,异或卷积由于涉及到乘法所以会比较慢,那我们用或卷积就好了!
code:
#include <bits/stdc++.h>
#define N (1<<21)
#define ll long long
#define mod 1000000009
#define lowbit(x) ((x)&(-(x)))
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,inv2,lim;
int f[N],g[N],A[21][N],B[21][N],C[21][N],cnt[N];
int qpow(int x,int y)
{
int tmp=1;
for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod;
return tmp;
}
int INV(int x) { return qpow(x,mod-2); }
void FWT(int *a)
{
for(int len=1;len<lim;len<<=1)
for(int i=0;i<lim;i+=len<<1)
for(int j=0;j<len;++j)
(a[i+j+len]+=a[i+j])%=mod;
}
void IFWT(int *a)
{
for(int len=1;len<lim;len<<=1)
for(int i=0;i<lim;i+=len<<1)
for(int j=0;j<len;++j)
(a[i+j+len]+=mod-a[i+j])%=mod;
}
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd()
{
int x=0; char c=nc();
while(c<48) c=nc();
while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc();
return x;
}
void print(int x) { if(x>=10) print(x/10); putchar(x%10+'0');}
int main()
{
// setIO("input");
n=rd(),lim=1<<n;
for(int i=0;i<lim;++i) f[i]=rd();
for(int i=0;i<lim;++i) g[i]=rd();
for(int i=1;i<lim;++i) cnt[i]=cnt[i-lowbit(i)]+1;
for(int i=0;i<lim;++i) A[cnt[i]][i]=f[i],B[cnt[i]][i]=g[i];
for(int i=0;i<=n;++i) FWT(A[i]),FWT(B[i]);
for(int i=0;i<=n;++i)
{
for(int j=0;j<=n;++j)
if(i+j<=n)
{
for(int k=0;k<lim;++k) (C[i+j][k]+=(ll)A[i][k]*B[j][k]%mod)%=mod;
}
}
for(int i=0;i<=n;++i) IFWT(C[i]);
for(int i=0;i<lim;++i) print(C[cnt[i]][i]),putchar(' ');
return 0;
}

浙公网安备 33010602011771号