FWT 是一种类似于 FFT 的一种变换,它可以实现在 O(nlogn) 的时间内求出
Ck=i&j=k∑AiBjCk=i∣j=k∑AiBjCk=i⊕j=k∑AiBj
由于 FWT 变换是一种线性变换,故满足 FWT(A)+FWT(B)=FWT(A+B)。
类似于 FFT 的方法,先将 A 补成 2k 的长度,每次将 A 拆成两半,分别求 FWT 即可。
因为 FWT 有 or,and,xor 三种形式,故也有三中不同的转移。
FWTor
FWT(A)={A(FWT(A0),FWT(A0)+FWT(A1)) n=0n>0
感性证明就是后面的一堆需要最高位为 0 的贡献,因为这是 or 运算。
然后 UFWT 就是把那个 + 换成 −。
考虑证明 FWT(A∣B)=FWT(A)×FWT(B)。(这里的 × 是按位乘)
FWT(A∣B)FWT(A0)×FWT(B0)+=FWT((A∣B)0,(A∣B)1)=FWT((A∣B)0,A0∣B1+A1∣B0+A1∣B1)=(FWT(A0∣B0),FWT(A0∣B0+A0∣B1+A1∣B0+A1∣B1))=(FWT(A0)×FWT(B0),FWT(A0)×FWT(B1)+FWT(A1)×FWT(B0)+FWT(A1)×FWT(B1))=(FWT(A0)×FWT(B0),(FWT(A0)+FWT(A1))×(FWT(B0)+FWT(B1)))=(FWT(A0),FWT(A0+A1))×(FWT(B0),FWT(B0+B1))=FWT(A)×FWT(B)
void FWT_or(int *a,int n,int ty)
{
for(int i=2;i<=n;i<<=1)
for(int j=0,p=i>>1;j<n;j+=i)
for(int k=j;k<j+p;k++)
a[k+p]+=ty*a[k];
return;
}
FWTand
FWT(A)={A(FWT(A0)+FWT(A1),FWT(A1)) n=0n>0
UFWT 也是将 + 变成 −,证明和上面的一样。
void FWT_and(int *a,int n,int ty)
{
for(int i=2;i<=n;i<<=1)
for(int j=0,p=i>>1;j<n;j+=i)
for(int k=j;k<j+p;k++)
a[k]+=ty*a[k+p];
return;
}
FWTxor
FWT(A)={A(FWT(A0)+FWT(A1),(FWT(A0)−FWT(A1)) n=0n>0
此时的 UFWT 变成 (2UFWT(A0)+UFWT(A1),2UFWT(A0)−UFWT(A1))。懒得证了。
void FWT_xor(int *a,int n,int ty)
{
for(int i=2;i<=n;i<<=1)
for(int j=0,p=i>>1;j<n;j+=i)
for(int k=j;k<j+p;k++)
{
int x=a[k],y=a[k+p];
if(ty==1)a[k]=(x+y)%mod,a[k+p]=(x-y+mod)%mod;
else a[k]=(x+y)%mod*inv2%mod,a[k+p]=(x-y+mod)%mod*inv2%mod;
}
return;
}