FWT-快速沃尔什变换

FWT-快速沃尔什变换

FWT有啥用啊

我们知道,FFT可以解决多项式的卷积,即

[C_k=sum_{i+j=k}A_i*B_j ]

如果将操作符换一下,换成集合运算符

比如

[C_k=sum_{i|j=k}A_i*B_j\C_k=sum_{i&j=k}A_i*B_j\C_k=sum_{ioplus j=k}A_i*B_j ]

这时就不能使用FFT

但是FFT使我们产生了一种想法

我们能不能用一种类似FFT的方法,用另一个多项式来表示(A,B),然后再对应相乘,最后再变换回来呢

答案是可以的,这就是FWT,即快速沃尔什变换

咋搞啊

我们以或运算举例:

我们按照定义,显然可以构造 (FWT[A] = A' = sum_{i=i|j}A_{j}) ,来表示 (j) 满足二进制中 (1)(i) 的子集。

那么显然会有 (C_{i} = sum_{i=j|k}A_{j}*B_{k} Rightarrow FWT[C] = FWT[A] * FWT[B])

至于上面这个是怎么来的:

[egin{aligned} FWT[C][i]&=FWT[A][i]*FWT[B][i]\ sum_{j|i}C_j&=(sum_{j|i}A_j)*(sum_{j|i}B_j) \ sum_{j|i}C_j&=sum_{j|i,k|i} A_jB_k\ sum_{j|i}C_j&=sum_{j|i}sum_{a|b=j}A_aB_b\ C_j&=sum_{a|b=j}A_aB_b end{aligned} ]

这样就和上面我们想要的式子一样了。

一堆定义/结论

别问我怎么推的,我也不知道。

这里有详细的证明。

通用性质

性质1:

[FWT(Apm B)=FWT(A)pm FWT(B) ]

性质2:

定义(oplus)为任意集合运算

[FWT(Aoplus B)=FWT(A)*FWT(B) (对应相乘) ]

或运算

定义:

[FWT(A)[i]=sum_{j|i=i}A_j ]

正向运算:

[FWT(A)=egin{cases}(FWT(A_0),FWT(A_1)+FWT(A_0))& n>1\ A & n=0end{cases} ]

逆向运算:

[IFWT(A)=egin{cases}(IFWT(A_0),IFWT(A_1)-IFWT(A_0))&n>1\ A&n=0end{cases} ]

与运算

定义:

[FWT(A)[i]=sum_{i&j=j}A_i ]

正向运算:

[FWT(A)=egin{cases}(FWT(A_0)+FWT(A_1),FWT(A_1))&n>1\ A &n=0end{cases} ]

逆向运算:

[IFWT(A)=egin{cases}(IFWT(A_0)-IFWT(A_1),IFWT(A_1))&n>1\ A&n=0end{cases} ]

异或运算

定义:

(d(x))(x)在二进制下拥有的1的数量

[FWT(A)[i]=sum_{d(j&i)为偶数}A_j-sum_{d(k&i)为奇数}A_k ]

正向运算:

[FWT(A)=egin{cases}(FWT(A_0)+FWT(A_1),FWT(A_0)-FWT(A_1))&n>0\ A&n=0end{cases} ]

逆向运算:

[IFWT(A)=egin{cases}(frac{IFWT(A_0+A_1)}{2},frac{IFWT(A_0-A_1)}{2})&n>1\ A&n=0end{cases} ]

板子

  1. 按位或
  2. 按位与
  3. 按位异或
//by Harry_bh
void FWT1(long long a[],int len)
{
	for(int mid=2;mid<=len;mid<<=1)
	for(int i=0;i<len;i+=mid)
	for(int j=i;j<i+(mid>>1);j++)a[j+(mid>>1)]+=a[j];
}
void IFWT1(long long a[],int len)
{
	for(int mid=2;mid<=len;mid<<=1)
	for(int i=0;i<len;i+=mid)
	for(int j=i;j<i+(mid>>1);j++)a[j+(mid>>1)]-=a[j];
}
void FWT2(long long a[],int len)
{
	for(int mid=2;mid<=len;mid<<=1)
	for(int i=0;i<len;i+=mid)
	for(int j=i;j<i+(mid>>1);j++)a[j]+=a[j+(mid>>1)];
}
void IFWT2(long long a[],int len)
{
	for(int mid=2;mid<=len;mid<<=1)
	for(int i=0;i<len;i+=mid)
	for(int j=i;j<i+(mid>>1);j++)a[j]-=a[j+(mid>>1)];
}
void FWT3(long long a[],int len)
{
	for(int mid=2;mid<=len;mid<<=1)
	for(int i=0;i<len;i+=mid)
	for(int j=i;j<i+(mid>>1);j++)
	{
		long long x=a[j],y=a[j+(mid>>1)];
		a[j]=x+y,a[j+(mid>>1)]=x-y;
	}
}
inline void IFWT3(long long a[],int len)
{
	for(int mid=2;mid<=len;mid<<=1)
	for(int i=0;i<len;i+=mid)
	for(int j=i;j<i+(mid>>1);j++)
	{
		long long x=a[j],y=a[j+(mid>>1)];
		a[j]=(x+y)>>1,a[j+(mid>>1)]=(x-y)>>1;
	}
}

参考资料

LSJ-FWT

OI-WIKI

原文地址:https://www.cnblogs.com/GavinZheng/p/11721127.html