廢話
是在 NOI Online 3 上被強行安利的科技……
模板題在你谷上都只有 人過qwq……
正題
是用來做這樣的卷積的:
如果沒有 這個條件那麼就是個 了,考慮怎麼處理這個東西。
不妨將每個數組增加一維,設 表示原來的 ,其中 表示集合 內有多少個元素,在二進制下就是 的個數。
那麼 這個限制就變成了 。
然後考慮將每個 進行 的正變換,然後像平常一樣 對應位置乘起來得到 ,不過要按照 的規則來加。
最後把每個 再逆變換回去,每個 就對應我們要的 。
這題有點神奇,用 來優化會變慢……
代碼如下:
#include <cstdio>
#define mod 1000000009
int n,cnt[1<<20];
int A[21][1<<20],B[21][1<<20],C[21][1<<20];
int add(int x,int y){return x+y<mod?x+y:x+y-mod;}
void FWT(int *f,int type)
{
for(int mid=1;mid<(1<<n);mid<<=1)
for(int j=0;j<(1<<n);j+=(mid<<1))
for(int i=j;i<j+mid;i++)f[i+mid]=add(f[i+mid],add(type*f[i],mod));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<(1<<n);i++)cnt[i]=cnt[i-(i&(-i))]+1;
for(int i=0;i<(1<<n);i++)scanf("%d",&A[cnt[i]][i]);
for(int i=0;i<(1<<n);i++)scanf("%d",&B[cnt[i]][i]);
for(int i=0;i<=n;i++)FWT(A[i],1),FWT(B[i],1);
for(int i=0;i<=n;i++)for(int j=0;j<=i;j++)
for(int k=0;k<(1<<n);k++)
C[i][k]=add(C[i][k],1ll*A[j][k]*B[i-j][k]%mod);
for(int i=0;i<=n;i++)FWT(C[i],-1);
for(int i=0;i<(1<<n);i++)printf("%d ",C[cnt[i]][i]);
}