快速沃尔什变换(FWT)详详详解

介绍

我们以前常见的多项式乘法长这个亚子:
C [ k ] = ∑ i + j = k A [ i ] × B [ j ] C[k]=\sum_{i+j=k}A[i]\times B[j] C[k]=i+j=kA[i]×B[j]

F W T FWT FWT 用来处理的,与 F F T FFT FFT 稍稍不同,是这样的卷积:
C [ k ] = ∑ i ⊕ j = k A [ i ] × B [ j ] C[k]=\sum_{i\oplus j=k}A[i]\times B[j] C[k]=ij=kA[i]×B[j]

其中, ⊕ \oplus 可以是 & , ∣ , Λ \&,|,\Lambda &,,Λ,这三种符号分别对应 a n d , o r , x o r and,or,xor and,or,xor

为了方便,首先做一些约定(下面 A , B A,B A,B 代表多项式):

A + B = ( A [ 0 ] + B [ 0 ] , A [ 1 ] + B [ 1 ] , ⋯   ) A+B=(A[0]+B[0],A[1]+B[1],\cdots) A+B=(A[0]+B[0],A[1]+B[1],),即按位相加
A − B = ( A [ 0 ] − B [ 0 ] , A [ 1 ] − B [ 1 ] , ⋯   ) A-B=(A[0]-B[0],A[1]-B[1],\cdots) AB=(A[0]B[0],A[1]B[1],),即按位相减
A ∗ B = ( A [ 0 ] × B [ 0 ] , A [ 1 ] × B [ 1 ] , ⋯   ) A*B=(A[0]\times B[0],A[1]\times B[1],\cdots) AB=(A[0]×B[0],A[1]×B[1],),即按位相乘(这个要注意,别和卷积搞混了)
A ⊕ B = ( ∑ i ⊕ j = 0 A [ i ] × B [ j ]   , ∑ i ⊕ j = 1 A [ i ] × B [ j ]   , ⋯   ) A\oplus B=(\sum\limits_{i\oplus j=0}A[i]\times B[j]~,\sum\limits_{i\oplus j=1}A[i]\times B[j]~,\cdots) AB=(ij=0A[i]×B[j] ,ij=1A[i]×B[j] ,),本质就是上面的那个卷积

思路

大致思路与 F F T FFT FFT 一致,将要卷在一起的两个多项式先正变换,然后按位相乘,最后逆变换回来即可。

或卷积

卷积的公式是这样的: C [ k ] = ∑ i ∣ j = k A [ i ] × B [ j ] C[k]=\sum\limits_{i|j=k}A[i]\times B[j] C[k]=ij=kA[i]×B[j]。可以表示为 C = A ∣ B C=A|B C=AB

其实或卷积与卷积的本质应该是 F M T FMT FMT,但是大部分人将它们归在 F W T FWT FWT 门下了,所以也放在这里讲。

正变换

定义: F W T ( A ) [ i ] = ∑ j ∣ i A [ j ] FWT(A)[i]=\sum_{j|i} A[j] FWT(A)[i]=jiA[j]。这个是正变换后得到的数组的意义,简单来说,就是下标的子集对应的位置之和,其中 j ∣ i j|i ji 表示 j j j i i i 的子集。


那么有一个很显然的性质:

F W T ( A ) + F W T ( B ) = F W T ( A + B ) FWT(A)+FWT(B)=FWT(A+B) FWT(A)+FWT(B)=FWT(A+B)

证明: 我们拿每一位单独看:

F W T ( A ) [ i ] = ∑ j ∣ i A [ j ] FWT(A)[i]=\sum_{j|i}A[j] FWT(A)[i]=jiA[j]
F W T ( B ) [ i ] = ∑ j ∣ i B [ j ] FWT(B)[i]=\sum_{j|i}B[j] FWT(B)[i]=jiB[j]
F W T ( A + B ) [ i ] = ∑ j ∣ i ( A + B ) [ j ] = ∑ j ∣ i A [ j ] + B [ j ] FWT(A+B)[i]=\sum_{j|i}(A+B)[j]=\sum_{j|i}A[j]+B[j] FWT(A+B)[i]=ji(A+B)[j]=jiA[j]+B[j]

嗯……很显然可以得到 F W T ( A ) [ i ] + F W T ( B ) [ i ] = F W T ( A + B ) [ i ] FWT(A)[i]+FWT(B)[i]=FWT(A+B)[i] FWT(A)[i]+FWT(B)[i]=FWT(A+B)[i]


再定义一个东西:设 A A A 这个多项式有 2 n 2^n 2n 项,那么 A 0 A_0 A0 表示前 2 n − 1 2^{n-1} 2n1 项, A 1 A_1 A1 表示后 2 n − 1 2^{n-1} 2n1 项。

那么其实很容易得到递归的公式:
F W T ( A ) = { ( F W T ( A 0 ) , F W T ( A 0 ) + F W T ( A 1 ) ) ( n > 0 ) A ( n = 0 ) FWT(A)= \begin{cases} (FWT(A_0),FWT(A_0)+FWT(A_1)) & (n>0)\\ A & (n=0) \end{cases} FWT(A)={(FWT(A0),FWT(A0)+FWT(A1))A(n>0)(n=0)

你问我 ( A , B ) (A,B) (A,B) 这样的表示是什么意思?别忘了 A , B A,B A,B 是多项式,你可以认为这是将两个多项式拼接在了一起。就像 A = ( A 0 , A 1 ) A=(A_0,A_1) A=(A0,A1)

证明

n = 0 n=0 n=0 时很显然,就不讲了。

仔细观察, A 0 A_0 A0 A 1 A_1 A1 的区别在于, A 0 A_0 A0 部分下标最高位是 0 0 0,而 A 1 A_1 A1 的最高位是 1 1 1,也就是说, A 0 A_0 A0 在对应位置上是 A 1 A_1 A1 的子集,因为只有最高位不一样,其他位都一样,所以我们将 A 0 A_0 A0 加给 A 1 A_1 A1

又因为 A 1 A_1 A1 中不可能有任何一位是 A 0 A_0 A0 的任意一个位置的子集,所以左半部分就只是 F W T ( A 0 ) FWT(A_0) FWT(A0)

这样递归下去,依次处理完第 n − 1 n-1 n1 位,第 n − 2 n-2 n2 位,……,第 1 1 1 位后,就求出了 F W T ( A ) FWT(A) FWT(A)

求解证明

求出 F W T ( A ) FWT(A) FWT(A) F W T ( B ) FWT(B) FWT(B) 之后,对应位置相乘就得到了 F W T ( C ) FWT(C) FWT(C),然后逆变换就可以得到多项式 C C C

这里就需要证明,为什么 F W T ( C ) = F W T ( A ∣ B ) = F W T ( A ) ∗ F W T ( B ) FWT(C)=FWT(A|B)=FWT(A)*FWT(B) FWT(C)=FWT(AB)=FWT(A)FWT(B)

感性理解

感性理解其实很简单, F W T ( A ) [ i ] FWT(A)[i] FWT(A)[i] 记录的是 i i i 的子集之和, F W T ( B ) [ i ] FWT(B)[i] FWT(B)[i] 也是,那么他们相乘,其实就是双方子集中的每一个元素两两相乘,取出来的两个元素的下标或起来一定还是 i i i 的子集中的一个,由于 C [ i ] C[i] C[i] 记录的是下标或起来为 i i i 的乘积之和,那么全部乘完之后,我们不仅得到了 C [ i ] C[i] C[i],还得到了 i i i 的所有子集的 C C C,也就是 F W T ( C ) [ i ] FWT(C)[i] FWT(C)[i]

理性证明

这玩意丑的很……相信没人想看的qwq,不过为了严谨,还是有必要写的啦。

下面为了区分属于…的子集或运算两个意思,就不都用 ∣ | 了,属于…的子集 ∈ \in 代替(只是在这个证明中)。
F W T ( C ) [ i ] = ∑ j ∈ i C [ j ] = ∑ j ∈ i ∑ x ∣ y = j A [ x ] × B [ y ] = ∑ ( x ∣ y ) ∈ i A [ x ] × B [ y ] = ∑ x ∈ i A [ x ] × ∑ y ∈ i B [ y ] = F W T ( A ) [ i ] × F W T ( B ) [ i ] \begin{aligned} FWT(C)[i]&=\sum_{j\in i}C[j]\\ &=\sum_{j\in i}\sum_{x|y=j}A[x]\times B[y]\\ &=\sum_{(x|y)\in i}A[x]\times B[y]\\ &=\sum_{x\in i}A[x]\times\sum_{y\in i}B[y]\\ &=FWT(A)[i]\times FWT(B)[i] \end{aligned} FWT(C)[i]=jiC[j]=jixy=jA[x]×B[y]=(xy)iA[x]×B[y]=xiA[x]×yiB[y]=FWT(A)[i]×FWT(B)[i]

逆变换

逆变换我们称为 I F W T IFWT IFWT,即满足 A = I F W T ( F W T ( A ) ) A=IFWT(FWT(A)) A=IFWT(FWT(A))

这个其实只需要将上面的加号变成减号即可。

感性理解

可以类比前缀和来理解:

//知道每个位置的值求前缀和
for(int i=1;i<=n;i++)a[i]+=a[i-1];
//知道前缀和求每个位置的值
for(int i=n;i>=1;i--)a[i]-=a[i-1];

理性证明

其实证明也很简单,以及与卷积异或卷积的理性证明其实都差不多。

证明: 我们现在已知 F W T ( A ) 0 , F W T ( A ) 1 FWT(A)_0,FWT(A)_1 FWT(A)0,FWT(A)1,要求 A 0 , A 1 A_0,A_1 A0,A1

∵ F W T ( A ) 0 = F W T ( A 0 ) \because FWT(A)_0=FWT(A_0) FWT(A)0=FWT(A0)
∴ A 0 = I F W T ( F W T ( A 0 ) ) = I F W T ( F W T ( A ) 0 ) \therefore A_0=IFWT(FWT(A_0))=IFWT(FWT(A)_0) A0=IFWT(FWT(A0))=IFWT(FWT(A)0)
∵ F W T ( A ) 1 = F W T ( A 0 ) + F W T ( A 1 ) \because FWT(A)_1=FWT(A_0)+FWT(A_1) FWT(A)1=FWT(A0)+FWT(A1),即 F W T ( A 1 ) = F W T ( A ) 1 − F W T ( A ) 0 FWT(A_1)=FWT(A)_1-FWT(A)_0 FWT(A1)=FWT(A)1FWT(A)0
∴ A 1 = I F W T ( F W T ( A 1 ) ) = I F W T ( F W T ( A ) 1 − F W T ( A ) 0 ) \therefore A_1=IFWT(FWT(A_1))=IFWT(FWT(A)_1-FWT(A)_0) A1=IFWT(FWT(A1))=IFWT(FWT(A)1FWT(A)0)

代码实现(其实和 F F T FFT FFT 很像):

void FWT_or(ll *f,int type)//type为1是正变换,-1是逆变换
{
	for(int mid=1;mid<n;mid<<=1)//每次将两块大小为mid的块合并成一个大块
	for(int block=mid<<1,j=0;j<n;j+=block)//枚举每个大块
	for(int i=j;i<j+mid;i++)//依次合并
	f[i+mid]=(f[i+mid]+f[i]*type+mod)%mod;
}

与卷积

卷积的公式是这样的: C [ k ] = ∑ i & j = k A [ i ] × B [ j ] C[k]=\sum\limits_{i\&j=k}A[i]\times B[j] C[k]=i&j=kA[i]×B[j]

正变换

定义: F W T ( A ) [ i ] = ∑ i ∣ j A [ j ] FWT(A)[i]=\sum_{i|j}A[j] FWT(A)[i]=ijA[j],意思就是, F W T ( A ) [ i ] FWT(A)[i] FWT(A)[i] 记录的是所有 A [ j ] A[j] A[j] 的和,其中 i , j i,j i,j 满足 i i i j j j 的子集。

这个显然也满足 F W T ( A ) + F W T ( B ) = F W T ( A + B ) FWT(A)+FWT(B)=FWT(A+B) FWT(A)+FWT(B)=FWT(A+B)

其实与卷积或卷积十分相似,一个是前面的对后面的产生贡献,一个是后面的对前面产生贡献。

类比或卷积,可以得到与卷积的递归公式:
F W T ( A ) = { ( F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A 1 ) ) ( n > 0 ) A ( n = 0 ) FWT(A)= \begin{cases} (FWT(A_0)+FWT(A_1),FWT(A_1)) & (n>0)\\ A & (n=0) \end{cases} FWT(A)={(FWT(A0)+FWT(A1),FWT(A1))A(n>0)(n=0)

证明

这就不用证了吧……和或卷积基本上一毛一样,就是 A 0 A_0 A0 A 1 A_1 A1 对应位置就差一个 1 1 1,所以 A 0 A_0 A0 A 1 A_1 A1 子集,所以把 A 1 A_1 A1 的贡献累加到 A 0 A_0 A0 上。

求解证明

如果理解了或运算的求解证明,那么与运算的其实也搞定了。

这里就直接贴一个数学证明了:
F W T ( C ) [ i ] = ∑ i ∈ j C [ j ] = ∑ i ∈ j ∑ x ∣ y = j A [ x ] × B [ y ] = ∑ i ∈ ( x ∣ y ) A [ x ] × B [ y ] = ∑ i ∈ x A [ x ] × ∑ i ∈ y B [ y ] = F W T ( A ) [ i ] × F W T ( B ) [ i ] \begin{aligned} FWT(C)[i]&=\sum_{i\in j}C[j]\\ &=\sum_{i\in j}\sum_{x|y=j}A[x]\times B[y]\\ &=\sum_{i\in(x|y)}A[x]\times B[y]\\ &=\sum_{i\in x}A[x]\times\sum_{i\in y}B[y]\\ &=FWT(A)[i]\times FWT(B)[i] \end{aligned} FWT(C)[i]=ijC[j]=ijxy=jA[x]×B[y]=i(xy)A[x]×B[y]=ixA[x]×iyB[y]=FWT(A)[i]×FWT(B)[i]

几乎就是一样的qwq

逆变换

也是很简单的将加号变减号。

证明: 我们现在已知 F W T ( A ) 0 , F W T ( A ) 1 FWT(A)_0,FWT(A)_1 FWT(A)0,FWT(A)1,要求 A 0 , A 1 A_0,A_1 A0,A1

∵ F W T ( A ) 1 = F W T ( A 1 ) \because FWT(A)_1=FWT(A_1) FWT(A)1=FWT(A1)
∴ A 1 = I F W T ( F W T ( A 1 ) ) = I F W T ( F W T ( A ) 1 ) \therefore A_1=IFWT(FWT(A_1))=IFWT(FWT(A)_1) A1=IFWT(FWT(A1))=IFWT(FWT(A)1)
∵ F W T ( A ) 0 = F W T ( A 0 ) + F W T ( A 1 ) \because FWT(A)_0=FWT(A_0)+FWT(A_1) FWT(A)0=FWT(A0)+FWT(A1),即 F W T ( A 0 ) = F W T ( A ) 1 − F W T ( A ) 0 FWT(A_0)=FWT(A)_1-FWT(A)_0 FWT(A0)=FWT(A)1FWT(A)0
∴ A 0 = I F W T ( F W T ( A 0 ) ) = I F W T ( F W T ( A ) 0 − F W T ( A ) 1 ) \therefore A_0=IFWT(FWT(A_0))=IFWT(FWT(A)_0-FWT(A)_1) A0=IFWT(FWT(A0))=IFWT(FWT(A)0FWT(A)1)

代码实现:

void FWT_and(ll *f,int type)
{
	for(int mid=1;mid<n;mid<<=1)
	for(int block=mid<<1,j=0;j<n;j+=block)
	for(int i=j;i<j+mid;i++)
	f[i]=(f[i]+f[i+mid]*type+mod)%mod;
}

异或卷积

这个东西才是真正的 F W T FWT FWT,求法都奇奇怪怪的。

卷积的公式是这样的: C [ k ] = ∑ i Λ j = k A [ i ] × B [ j ] C[k]=\sum\limits_{i\Lambda j=k}A[i]\times B[j] C[k]=iΛj=kA[i]×B[j]

正变换

首先摒弃上面带来的一些奇奇怪怪的想法,因为异或卷积的正变换没有用到异或,完全没有。

c ( i ) c(i) c(i) 表示 i i i 的二进制有多少个 1 1 1,如 c ( 3 ) = 2 c(3)=2 c(3)=2

奇怪的定义: F W T ( A ) [ i ] = ∑ j = 0 2 n − 1 ( − 1 ) c ( i & j ) A [ j ] FWT(A)[i]=\sum\limits_{j=0}^{2^n-1}(-1)^{c(i\&j)}A[j] FWT(A)[i]=j=02n1(1)c(i&j)A[j],也可以写成 F W T ( A ) [ i ] = ( ∑ c ( i & j )   m o d   2 = 0 A [ j ] ) − ( ∑ c ( i & k )   m o d   2 = 1 A [ k ] ) FWT(A)[i]=(\sum\limits_{c(i\&j)\bmod 2=0}A[j])-(\sum\limits_{c(i\&k)\bmod 2=1}A[k]) FWT(A)[i]=(c(i&j)mod2=0A[j])(c(i&k)mod2=1A[k])

没错,是 & \& & 不是 Λ \Lambda Λ。不用管为什么,看下去就知道了,重点是记住定义。

递归公式:
F W T ( A ) = { ( F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A 0 ) − F W T ( A 1 ) ) ( n > 0 ) A ( n = 0 ) FWT(A)= \begin{cases} (FWT(A_0)+FWT(A_1),FWT(A_0)-FWT(A_1)) & (n>0)\\ A & (n=0) \end{cases} FWT(A)={(FWT(A0)+FWT(A1),FWT(A0)FWT(A1))A(n>0)(n=0)

怎么样,是不是有种见了鬼的感觉qwq

但是实际上不难理解。

证明

依然忽略 n = 0 n=0 n=0 时的情况~

此时要理解,求出来的 F W T ( A 1 ) FWT(A_1) FWT(A1) 并没有考虑到他是 A A A 的右半部分,即最高位的 1 1 1 是没有考虑的,也就是说,求 F W T ( A 1 ) FWT(A_1) FWT(A1) 时下标是 0 0 0 ~ 2 n − 1 − 1 2^{n-1}-1 2n11,而不是 2 n − 1 2^{n-1} 2n1 ~ 2 n − 1 2^n-1 2n1

剩下的我们从左到右看:

首先 F W T ( A ) 0 = F W T ( A 0 ) + F W T ( A 1 ) FWT(A)_0=FWT(A_0)+FWT(A_1) FWT(A)0=FWT(A0)+FWT(A1),因为 F W T ( A ) 0 FWT(A)_0 FWT(A)0 是左半部分,于是最高位是 0 0 0,所以不管是和左半部分做与运算还是与右半部分做与运算,最高位都是 0 0 0,所以直接把左右两边的贡献加起来即可。

F W T ( A ) 1 FWT(A)_1 FWT(A)1 比较特殊,他是右半部分,所以他与右半部分做与运算时,最高位多出来一个 1 1 1,而这是 F W T ( A 1 ) FWT(A_1) FWT(A1) 没有考虑到的,如果多了个 1 1 1 的话,回看上面的定义, c ( i & j ) c(i\&j) c(i&j) 就会乘多一个 − 1 -1 1,所以 F W T ( A 1 ) FWT(A_1) FWT(A1) 的贡献是负的。而 F W T ( A 0 ) FWT(A_0) FWT(A0) 无所谓,由于它本身就在左半部分,不会多出最高位的 1 1 1,所以贡献是正的。

求解证明

这里就用到异或了,以及用到了一个性质(描述有点长qwq,不想看的可以直接看下面的柿子): i i i k k k 1 1 1 的数量的奇偶性异或 j j j k k k 1 1 1 的数量的奇偶性等于 i i i 异或 j j j k k k 1 1 1 的数量的奇偶性相同。

用数学柿子来表示的话,设 P ( i ) P(i) P(i) 表示 i i i 的奇偶性,当 i i i 是奇数时 P ( i ) = 1 P(i)=1 P(i)=1,当 i i i 是偶数时 P ( i ) = 0 P(i)=0 P(i)=0,那么这个性质就是:
P ( c ( i & k ) ) Λ P ( c ( j & k ) ) = P ( c ( ( i Λ j ) & k ) ) P(c(i\&k))\Lambda P(c(j\&k))=P(c((i\Lambda j)\&k)) P(c(i&k))ΛP(c(j&k))=P(c((iΛj)&k))

为了严谨,证明还是要有的(其实随便手玩一下就懂了,很简单):

考虑 i , j , k i,j,k i,j,k 的某一位,记为 x , y , z x,y,z x,y,z(注意,是同一位),那么有两种情况(已经尽力压缩了qwq,怕多了各位不看呀,下面这些看起来繁琐的东西其实逻辑很简单的,静心细看就好):

  1. x , y x,y x,y 都等于或不等于 z z z(即 x = y x=y x=y)。那么 i & k i\&k i&k j & k j\&k j&k 的这一位相同,所以 c ( i & k ) c(i\&k) c(i&k) c ( j & k ) c(j\&k) c(j&k) 同时 + 1 +1 +1 + 0 +0 +0 P ( c ( i & k ) ) Λ P ( c ( j & k ) ) P(c(i\&k))\Lambda P(c(j\&k)) P(c(i&k))ΛP(c(j&k)) 的值不变。再看等式右边, i Λ j i\Lambda j iΛj 的这一位为 0 0 0,那么 ( i Λ j ) & k (i\Lambda j)\&k (iΛj)&k 的这一位就是 0 0 0,对 c ( ( i Λ j ) & k ) c((i\Lambda j)\&k) c((iΛj)&k) 没有贡献,所以 P ( c ( ( i Λ j ) & k ) ) P(c((i\Lambda j)\&k)) P(c((iΛj)&k)) 也不会变,等式成立。
  2. x , y x,y x,y 一个等于 z z z,一个不等于 z z z(即 x ≠ y x\neq y x=y)。假如 z = 0 z=0 z=0,那么参照情况 1 1 1,很容易知道此时两边又是不会发生变化的。如果 z = 1 z=1 z=1,此时 i & k i\&k i&k j & k j\&k j&k 的这一位不同,所以 c ( i & k ) c(i\&k) c(i&k) c ( j & k ) c(j\&k) c(j&k) 一个 + 1 +1 +1,一个 + 0 +0 +0,那么等式左边就会发生变化。而右边因为 i Λ j i\Lambda j iΛj k k k 的这一位同时为 1 1 1,所以 c ( ( i Λ j ) & k ) c((i\Lambda j)\&k) c((iΛj)&k) + 1 +1 +1,那么等式右边也会发生变化。等式两边同时变化,等式依然成立。

接下来就是求解的证明了,还是像上面那样大力展开(自己手(luan)推的,要是错了告知一下谢谢啦qwq):
F W T ( C ) [ i ] = ∑ j = 0 2 n − 1 ( − 1 ) c ( i & j ) C [ j ] = ∑ j = 0 2 n − 1 ( − 1 ) c ( i & j ) ∑ x Λ y = j A [ x ] × B [ y ] = ∑ x = 0 2 n − 1 ∑ y = 0 2 n − 1 A [ x ] × B [ y ] × ( − 1 ) c ( i & ( x Λ y ) ) \begin{aligned} FWT(C)[i]&=\sum\limits_{j=0}^{2^n-1}(-1)^{c(i\&j)}C[j]\\ &=\sum\limits_{j=0}^{2^n-1}(-1)^{c(i\&j)}\sum_{x\Lambda y=j} A[x]\times B[y]\\ &=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{c(i\&(x\Lambda y))} \end{aligned} FWT(C)[i]=j=02n1(1)c(i&j)C[j]=j=02n1(1)c(i&j)xΛy=jA[x]×B[y]=x=02n1y=02n1A[x]×B[y]×(1)c(i&(xΛy))

诶!仔细观察发现,我们只在意 c ( i & ( x Λ y ) ) c(i\&(x\Lambda y)) c(i&(xΛy)) 的奇偶性,因为他是 − 1 -1 1 的指数,所以我们不妨在外面套一个 P P P,显然是不影响答案的。
= ∑ x = 0 2 n − 1 ∑ y = 0 2 n − 1 A [ x ] × B [ y ] × ( − 1 ) P ( c ( i & ( x Λ y ) ) ) =\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&(x\Lambda y)))} =x=02n1y=02n1A[x]×B[y]×(1)P(c(i&(xΛy)))

这不就是上面性质里的样子吗!于是我们可以愉快的拆开啦:
= ∑ x = 0 2 n − 1 ∑ y = 0 2 n − 1 A [ x ] × B [ y ] × ( − 1 ) P ( c ( i & x ) )   Λ   P ( c ( i & y ) ) =\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&x))~\Lambda ~P(c(i\&y))} =x=02n1y=02n1A[x]×B[y]×(1)P(c(i&x)) Λ P(c(i&y))

仔细观察下面的柿子,是不是有什么规律?

( − 1 ) 0 Λ 0 =     1 = ( − 1 ) 0 + 0 (-1)^{0\Lambda 0}=~~~1=(-1)^{0+0} (1)0Λ0=   1=(1)0+0
( − 1 ) 0 Λ 1 = − 1 = ( − 1 ) 0 + 1 (-1)^{0\Lambda 1}=-1=(-1)^{0+1} (1)0Λ1=1=(1)0+1
( − 1 ) 1 Λ 0 = − 1 = ( − 1 ) 1 + 0 (-1)^{1\Lambda 0}=-1=(-1)^{1+0} (1)1Λ0=1=(1)1+0
( − 1 ) 1 Λ 1 =     1 = ( − 1 ) 1 + 1 (-1)^{1\Lambda 1}=~~~1=(-1)^{1+1} (1)1Λ1=   1=(1)1+1

没错!将指数里的 Λ \Lambda Λ 换成 + + + 并不影响答案!

接下来就可以顺理成章的证明下去了。
= ∑ x = 0 2 n − 1 ∑ y = 0 2 n − 1 A [ x ] × B [ y ] × ( − 1 ) P ( c ( i & x ) ) + P ( c ( i & y ) ) = ∑ x = 0 2 n − 1 ∑ y = 0 2 n − 1 A [ x ] × B [ y ] × ( − 1 ) P ( c ( i & x ) ) × ( − 1 ) P ( c ( i & y ) ) = ∑ x = 0 2 n − 1 A [ x ] × ( − 1 ) P ( c ( i & x ) ) × ∑ y = 0 2 n − 1 B [ y ] × ( − 1 ) P ( c ( i & y ) ) = F W T ( A ) [ i ] × F W T ( B ) [ i ] \begin{aligned} &=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&x))+P(c(i\&y))}\\ &=\sum_{x=0}^{2^n-1}\sum_{y=0}^{2^n-1}A[x]\times B[y]\times(-1)^{P(c(i\&x))}\times(-1)^{P(c(i\&y))}\\ &=\sum_{x=0}^{2^n-1}A[x]\times (-1)^{P(c(i\&x))} \times \sum_{y=0}^{2^n-1}B[y]\times (-1)^{P(c(i\&y))}\\ &=FWT(A)[i]\times FWT(B)[i] \end{aligned} =x=02n1y=02n1A[x]×B[y]×(1)P(c(i&x))+P(c(i&y))=x=02n1y=02n1A[x]×B[y]×(1)P(c(i&x))×(1)P(c(i&y))=x=02n1A[x]×(1)P(c(i&x))×y=02n1B[y]×(1)P(c(i&y))=FWT(A)[i]×FWT(B)[i]

逆变换

这个就稍微跟上面不一样的,不过一样的是都很容易理解~

A ′ = F W T ( A ) A'=FWT(A) A=FWT(A),那么逆变换递推公式就是:
{ ( I F W T ( A 0 ′ ) + I F W T ( A 1 ′ ) 2 , I F W T ( A 0 ′ ) − I F W T ( A 1 ′ ) 2 ) ( n > 0 ) A ′ ( n = 0 ) \begin{cases} (\frac {IFWT(A'_0)+IFWT(A'_1)} 2,\frac {IFWT(A'_0)-IFWT(A'_1)} 2) & (n>0)\\ A' & (n=0) \end{cases} {(2IFWT(A0)+IFWT(A1),2IFWT(A0)IFWT(A1))A(n>0)(n=0)

证明: 现在已知 F W T ( A ) 0 , F W T ( A ) 1 FWT(A)_0,FWT(A)_1 FWT(A)0,FWT(A)1,求 A 0 , A 1 A_0,A_1 A0,A1

∵ F W T ( A ) 0 = F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A ) 1 = F W T ( A 0 ) − F W T ( A 1 ) \because FWT(A)_0=FWT(A_0)+FWT(A_1),FWT(A)_1=FWT(A_0)-FWT(A_1) FWT(A)0=FWT(A0)+FWT(A1),FWT(A)1=FWT(A0)FWT(A1)
∴ F W T ( A 0 ) = F W T ( A ) 0 + F W T ( A ) 1 2 , F W T ( A 1 ) = F W T ( A ) 0 − F W T ( A ) 1 2 \therefore FWT(A_0)=\frac {FWT(A)_0+FWT(A)_1} 2,FWT(A_1)=\frac {FWT(A)_0-FWT(A)_1} 2 FWT(A0)=2FWT(A)0+FWT(A)1,FWT(A1)=2FWT(A)0FWT(A)1
∴ A 0 = I F W T ( F W T ( A 0 ) ) = I F W T ( F W T ( A ) 0 + F W T ( A ) 1 2 ) \therefore A_0=IFWT(FWT(A_0))=IFWT(\frac {FWT(A)_0+FWT(A)_1} 2) A0=IFWT(FWT(A0))=IFWT(2FWT(A)0+FWT(A)1)
     A 1 = I F W T ( F W T ( A 1 ) ) = I F W T ( F W T ( A ) 0 − F W T ( A ) 1 2 ) ~~~~A_1=IFWT(FWT(A_1))=IFWT(\frac {FWT(A)_0-FWT(A)_1} 2)     A1=IFWT(FWT(A1))=IFWT(2FWT(A)0FWT(A)1)

代码实际上也没比上面的麻烦多少:

void FWT_xor(ll *f,int type)
{
	for(int mid=1;mid<n;mid<<=1)
	for(int block=mid<<1,j=0;j<n;j+=block)
	for(int i=j;i<j+mid;i++)//这三个循环与上面完全一样
	{
		ll x=f[i],y=f[i+mid];
		f[i]=(x+y)%mod*(type==1?1:inv_2)%mod;
		f[i+mid]=(x-y+mod)%mod*(type==1?1:inv_2)%mod;
	}
}

模板题

题目传送门

#include <cstdio>
#include <cstring>
#define ll long long
#define mod 998244353
#define maxn 1<<18

int n;
ll a[maxn],b[maxn],A[maxn],B[maxn];
void FWT_or(ll *f,int type)
{
	for(int mid=1;mid<n;mid<<=1)
	for(int block=mid<<1,j=0;j<n;j+=block)
	for(int i=j;i<j+mid;i++)
	f[i+mid]=(f[i+mid]+f[i]*type+mod)%mod;
}
void FWT_and(ll *f,int type)
{
	for(int mid=1;mid<n;mid<<=1)
	for(int block=mid<<1,j=0;j<n;j+=block)
	for(int i=j;i<j+mid;i++)
	f[i]=(f[i]+f[i+mid]*type+mod)%mod;
}
int inv_2=499122177;
void FWT_xor(ll *f,int type)
{
	for(int mid=1;mid<n;mid<<=1)
	for(int block=mid<<1,j=0;j<n;j+=block)
	for(int i=j;i<j+mid;i++)
	{
		ll x=f[i],y=f[i+mid];
		f[i]=(x+y)%mod*(type==1?1:inv_2)%mod;
		f[i+mid]=(x-y+mod)%mod*(type==1?1:inv_2)%mod;
	}
}
void work(void (*FWT)(ll *f,int type))//将函数作为参数传入
{
	for(int i=0;i<n;i++)a[i]=A[i],b[i]=B[i];
	FWT(a,1);FWT(b,1);
	for(int i=0;i<n;i++)a[i]=a[i]*b[i]%mod;
	FWT(a,-1);
	for(int i=0;i<n;i++)printf("%lld ",a[i]);
	printf("\n");
}

int main()
{
	scanf("%d",&n);n=1<<n;
	for(int i=0;i<n;i++)scanf("%lld",&A[i]),A[i]%=mod;
	for(int i=0;i<n;i++)scanf("%lld",&B[i]),B[i]%=mod;
	work(FWT_or);work(FWT_and);work(FWT_xor);
}
  • 16
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值