定义
AAA和BBB均是长度为n=2kn=2^kn=2k的数组。定义A0A_0A0为这个数组的前2n−12^{n-1}2n−1项,A1A_1A1为这个数组的后2n−12^{n-1}2n−1项,那么有A=(A0,A1)A=(A_0,A_1)A=(A0,A1)。
A+B=(A[0]+B[0],A[1]+B[1],...,A[n−1]+B[n−1])A+B=(A[0]+B[0],A[1]+B[1],...,A[n-1]+B[n-1])A+B=(A[0]+B[0],A[1]+B[1],...,A[n−1]+B[n−1])
A∗B=(A[0]∗B[0],A[1]∗B[1],...,A[n−1]∗B[n−1])A*B=(A[0]*B[0],A[1]*B[1],...,A[n-1]*B[n-1])A∗B=(A[0]∗B[0],A[1]∗B[1],...,A[n−1]∗B[n−1])
A@B=(∑i@j=0A[i]∗B[j],∑i@j=1A[i]∗B[j],...,∑i@j=n−1A[i]∗B[j])A@B=(\sum_{i@j=0}A[i]*B[j],\sum_{i@j=1}A[i]*B[j],...,\sum_{i@j=n-1}A[i]*B[j])A@B=(∑i@j=0A[i]∗B[j],∑i@j=1A[i]∗B[j],...,∑i@j=n−1A[i]∗B[j])
目标
给出A,BA,BA,B,求C=A@BC=A@BC=A@B。
快速沃尔什变换
快速沃尔什变换(简称FWT),就是用来解决这样一类问题的算法。其中@@@运算可以是异或,与,或之类的位运算。
这里主要介绍异或运算。
XOR
根据异或运算的性质,不难得到A@B=(A0⊕B0+A1⊕B1,A0⊕B1+A1⊕B0)A@B=(A_0\oplus B_0+A_1\oplus B_1,A_0\oplus B_1+A_1\oplus B_0)A@B=(A0⊕B0+A1⊕B1,A0⊕B1+A1⊕B0)。
且不难验证⊕\oplus⊕运算满足交换律,分配律和结合律。
定义运算Fwt(A)Fwt(A)Fwt(A)为
Fwt(A)={(Fwt(A0+A1),Fwt(A0−A1))n>1An=1Fwt(A) = \begin{cases}
(Fwt(A_0+A_1),Fwt(A_0-A_1)) & n>1 \\
A & n=1
\end{cases}Fwt(A)={(Fwt(A0+A1),Fwt(A0−A1))An>1n=1
性质1
Fwt(A+B)=Fwt(A)+Fwt(B)Fwt(A+B)=Fwt(A)+Fwt(B)Fwt(A+B)=Fwt(A)+Fwt(B)
证明:不难发现Fwt(A)Fwt(A)Fwt(A)的每一项都是AAA的一个线性组合,故满足加法分配律。
性质2
Fwt(A⊕B)=Fwt(A)∗Fwt(B)Fwt(A\oplus B)=Fwt(A)*Fwt(B)Fwt(A⊕B)=Fwt(A)∗Fwt(B)
证明:用数学归纳法来证。
当n=1n=1n=1时显然成立。
当n>1n>1n>1时有
Fwt(A⊕B)Fwt(A\oplus B)Fwt(A⊕B)
=Fwt(A0⊕B0+A1⊕B1,A0⊕B1+A1⊕B0)=Fwt(A_0\oplus B_0+A_1\oplus B_1,A_0\oplus B_1+A_1\oplus B_0)=Fwt(A0⊕B0+A1⊕B1,A0⊕B1+A1⊕B0)
=(Fwt(A0⊕B0+A1⊕B1+A0⊕B1+A1⊕B0),Fwt(A0⊕B0+A1⊕B1−A0⊕B1−A1⊕B0))=(Fwt(A_0\oplus B_0+A_1\oplus B_1+A_0\oplus B_1+A_1\oplus B_0),Fwt(A_0\oplus B_0+A_1\oplus B_1-A_0\oplus B_1-A_1\oplus B_0))=(Fwt(A0⊕B0+A1⊕B1+A0⊕B1+A1⊕B0),Fwt(A0⊕B0+A1⊕B1−A0⊕B1−A1⊕B0))
=(Fwt((A0+A1)⊕(B0+B1)),Fwt((A0−A1)⊕(B0−B1)))=(Fwt((A_0+A_1)\oplus (B_0+B_1)),Fwt((A_0-A_1)\oplus (B_0-B_1)))=(Fwt((A0+A1)⊕(B0+B1)),Fwt((A0−A1)⊕(B0−B1)))
=(Fwt(A0+A1)∗Fwt(B0+B1),Fwt(A0−A1)∗Fwt(B0−B1))=(Fwt(A_0+A_1)*Fwt(B_0+B_1),Fwt(A_0-A_1)*Fwt(B_0-B_1))=(Fwt(A0+A1)∗Fwt(B0+B1),Fwt(A0−A1)∗Fwt(B0−B1))
=(Fwt(A)0∗Fwt(B)0,Fwt(A)1∗Fwt(B)1)=(Fwt(A)_0*Fwt(B)_0,Fwt(A)_1*Fwt(B)_1)=(Fwt(A)0∗Fwt(B)0,Fwt(A)1∗Fwt(B)1)
=Fwt(A)∗Fwt(B)=Fwt(A)*Fwt(B)=Fwt(A)∗Fwt(B)
证毕。
逆变换
Dwt(Fwt(A))Dwt(Fwt(A))Dwt(Fwt(A))
=Dwt(Fwt(A0+A1),Fwt(A0−A1))=Dwt(Fwt(A_0+A_1),Fwt(A_0-A_1))=Dwt(Fwt(A0+A1),Fwt(A0−A1))
=Dwt(Fwt(A0)+Fwt(A1),Fwt(A0)−Fwt(A1))=Dwt(Fwt(A_0)+Fwt(A_1),Fwt(A_0)-Fwt(A_1))=Dwt(Fwt(A0)+Fwt(A1),Fwt(A0)−Fwt(A1))
令Dwt(A)=(Dwt(A0+A12),Dwt(A0−A12))Dwt(A)=(Dwt(\frac{A_0+A_1}{2}),Dwt(\frac{A_0-A_1}{2}))Dwt(A)=(Dwt(2A0+A1),Dwt(2A0−A1))
那么有Dwt(Fwt(A))Dwt(Fwt(A))Dwt(Fwt(A))
=(Dwt(Fwt(A0)),Dwt(Fwt(A1)))=(Dwt(Fwt(A_0)),Dwt(Fwt(A_1)))=(Dwt(Fwt(A0)),Dwt(Fwt(A1)))
=(A0,A1)=(A_0,A_1)=(A0,A1)
求解
在求解C=A⊕BC=A\oplus BC=A⊕B的时候,可以先对AAA和BBB分别做FwtFwtFwt,得到A′A'A′和B′B'B′。
设C′=A′∗B′C'=A'*B'C′=A′∗B′,那么C=Dwt(C′)C=Dwt(C')C=Dwt(C′)。
时间复杂度O(nlogn)O(nlogn)O(nlogn)。
代码
void fwt(int *a,int l,int r)
{
if (l==r) return;
int n=(r-l+1)/2,mid=l+n-1;
fwt(a,l,mid);fwt(a,mid+1,r);
for (int i=l;i<=mid;i++)
{
int x=a[i],y=a[i+n];
a[i]=x+y;a[i+n]=x-y;
}
}
void dwt(int *a,int l,int r)
{
if (l==r) return;
int n=(r-l+1)/2,mid=l+n-1;
dwt(a,l,mid);dwt(a,mid+1,r);
for (int i=l;i<=mid;i++)
{
int x=a[i],y=a[i+n];
a[i]=(x+y)/2;a[i+n]=(x-y)/2;
}
}
AND
当@@@为与运算的时候,通过上述方法不难验证
Fwt(A)=(Fwt(A0+A1),Fwt(A1))Fwt(A)=(Fwt(A_0+A_1),Fwt(A_1))Fwt(A)=(Fwt(A0+A1),Fwt(A1))
Dwt(A)=(Dwt(A0−A1),Fwt(A1))Dwt(A)=(Dwt(A_0-A_1),Fwt(A_1))Dwt(A)=(Dwt(A0−A1),Fwt(A1))
OR
当@@@为或运算的时候,通过类比与运算不难验证
Fwt(A)=(Fwt(A0),Fwt(A0+A1))Fwt(A)=(Fwt(A_0),Fwt(A_0+A_1))Fwt(A)=(Fwt(A0),Fwt(A0+A1))
Dwt(A)=(Dwt(A0),Dwt(A1−A0))Dwt(A)=(Dwt(A_0),Dwt(A_1-A_0))Dwt(A)=(Dwt(A0),Dwt(A1−A0))