Description
太长自己看系列。。
Solution
记c[i]为i二进制下1的数量,
d
[
i
]
=
b
[
c
[
i
]
]
d[i]=b[c[i]]
d[i]=b[c[i]],那么柿子就是
e
′
[
i
]
=
∑
x
e
[
x
]
∗
d
[
i
⊕
x
]
e'[i]=\sum\limits_{x}e[x]*d[i\oplus x]
e′[i]=x∑e[x]∗d[i⊕x]
然后就是非常套路的换下标了,
(
i
⊕
x
)
⊕
x
=
i
(i\oplus x)\oplus x=i
(i⊕x)⊕x=i
于是
e
′
[
i
]
=
∑
x
⊕
y
=
i
e
[
x
]
∗
d
[
y
]
e'[i]=\sum\limits_{x\oplus y=i}e[x]*d[y]
e′[i]=x⊕y=i∑e[x]∗d[y],由于每一次卷上的d都是不变的,因此可以快速幂预处理
还有一个问题是膜数不一定存在逆元,注意到FWT的写法是酱的
void FWT(LL *a,int n,int f) {
for (int i=1;i<n;i<<=1) {
for (int j=0;j<n;j+=(i<<1)) {
for (int k=0;k<i;++k) {
LL u=a[j+k],v=a[j+k+i];
a[j+k]=(u+v)%MOD;
a[j+k+i]=(u-v+MOD)%MOD;
}
}
}
if (f==-1) for (int i=0;i<n;++i) a[i]/=n;
}
酱的
void FWT(int *a,int n,int f) {
for (int i=1;i<n;i<<=1) {
for (int j=0;j<n;j+=(i<<1)) {
for (int k=0;k<i;++k) {
int u=a[j+k],v=a[j+k+i];
a[j+k]=(u+v)%MOD,a[j+k+i]=(u+MOD-v)%MOD;
if (f==-1) {
a[j+k]=1LL*a[j+k]*ny2%MOD;
a[j+k+i]=1LL*a[j+k+i]*ny2%MOD;
}
}
}
}
}
以上两种都是对的。考虑第一种做法,那么我们可以把膜数*n,最后FWT回来的时候除掉n就可以了
膜数变得很大因此需要快速乘黑科技
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define copy(x,t) memcpy(x,t,sizeof(x))
typedef long long LL;
const int N=2000005;
LL a[N],b[N],c[N],d[N],e[N];
LL MOD;
LL mul(LL x,LL y) {
LL res=x*y-(LL)((long double)x/MOD*y+0.1)*MOD;
return (res%MOD+MOD)%MOD;
}
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void FWT(LL *a,int n,int f) {
for (int i=1;i<n;i<<=1) {
for (int j=0;j<n;j+=(i<<1)) {
for (int k=0;k<i;++k) {
LL u=a[j+k],v=a[j+k+i];
a[j+k]=(u+v)%MOD;
a[j+k+i]=(u-v+MOD)%MOD;
}
}
}
if (f==-1) for (int i=0;i<n;++i) a[i]/=n;
}
int main(void) {
int n; LL m,lim;
scanf("%d%lld%lld",&n,&m,&MOD);
lim=1LL<<n; MOD*=lim;
rep(i,0,lim-1) a[i]=read();
rep(i,0,lim-1) c[i]=c[i>>1]+(i&1);
rep(i,0,n) b[i]=read();
rep(i,0,lim-1) d[i]=b[c[i]];
FWT(d,lim,1); copy(e,d);
for (m--;m;m>>=1) {
if (m&1) for (int i=0;i<lim;++i) e[i]=mul(e[i],d[i]);
for (int i=0;i<lim;++i) d[i]=mul(d[i],d[i]);
}
FWT(a,lim,1);
for (int i=0;i<lim;++i) a[i]=mul(a[i],e[i]);
FWT(a,lim,-1);
for (int i=0;i<lim;++i) printf("%lld\n", a[i]);
return 0;
}