文章目录

  • 介绍
  • 思路
  • 或卷积
    • 正变换
      • 证明
    • 求解证明
      • 感性理解
      • 理性证明
    • 逆变换
      • 感性理解
      • 理性证明
  • 与卷积
    • 正变换
      • 证明
    • 求解证明
    • 逆变换
  • 异或卷积
    • 正变换
      • 证明
    • 求解证明
    • 逆变换
  • 模板题

介绍

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

而 FWTFWTFWT 用来处理的,与 FFTFFTFFT 稍稍不同,是这样的卷积:
C[k]=∑i⊕j=kA[i]×B[j]C[k]=\sum_{i\oplus j=k}A[i]\times B[j] C[k]=i⊕j=k∑​A[i]×B[j]

其中,⊕\oplus⊕ 可以是 &,∣,Λ\&,|,\Lambda&,∣,Λ,这三种符号分别对应 and,or,xorand,or,xorand,or,xor。

为了方便,首先做一些约定(下面 A,BA,BA,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)A−B=(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)A∗B=(A[0]×B[0],A[1]×B[1],⋯),即按位相乘(这个要注意,别和卷积搞混了)
A⊕B=(∑i⊕j=0A[i]×B[j],∑i⊕j=1A[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)A⊕B=(i⊕j=0∑​A[i]×B[j] ,i⊕j=1∑​A[i]×B[j] ,⋯),本质就是上面的那个卷积

思路

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

或卷积

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

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

正变换

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


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

FWT(A)+FWT(B)=FWT(A+B)FWT(A)+FWT(B)=FWT(A+B)FWT(A)+FWT(B)=FWT(A+B)

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

FWT(A)[i]=∑j∣iA[j]FWT(A)[i]=\sum_{j|i}A[j]FWT(A)[i]=∑j∣i​A[j]
FWT(B)[i]=∑j∣iB[j]FWT(B)[i]=\sum_{j|i}B[j]FWT(B)[i]=∑j∣i​B[j]
FWT(A+B)[i]=∑j∣i(A+B)[j]=∑j∣iA[j]+B[j]FWT(A+B)[i]=\sum_{j|i}(A+B)[j]=\sum_{j|i}A[j]+B[j]FWT(A+B)[i]=∑j∣i​(A+B)[j]=∑j∣i​A[j]+B[j]

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


再定义一个东西:设 AAA 这个多项式有 2n2^n2n 项,那么 A0A_0A0​ 表示前 2n−12^{n-1}2n−1 项,A1A_1A1​ 表示后 2n−12^{n-1}2n−1 项。

那么其实很容易得到递归的公式:
FWT(A)={(FWT(A0),FWT(A0)+FWT(A1))(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,BA,BA,B 是多项式,你可以认为这是将两个多项式拼接在了一起。就像 A=(A0,A1)A=(A_0,A_1)A=(A0​,A1​)。

证明

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

仔细观察,A0A_0A0​ 与 A1A_1A1​ 的区别在于,A0A_0A0​ 部分下标最高位是 000,而 A1A_1A1​ 的最高位是 111,也就是说,A0A_0A0​ 在对应位置上是 A1A_1A1​ 的子集,因为只有最高位不一样,其他位都一样,所以我们将 A0A_0A0​ 加给 A1A_1A1​。

又因为 A1A_1A1​ 中不可能有任何一位是 A0A_0A0​ 的任意一个位置的子集,所以左半部分就只是 FWT(A0)FWT(A_0)FWT(A0​)。

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

求解证明

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

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

感性理解

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

理性证明

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

下面为了区分属于…的子集或运算两个意思,就不都用 ∣|∣ 了,属于…的子集用 ∈\in∈ 代替(只是在这个证明中)。
FWT(C)[i]=∑j∈iC[j]=∑j∈i∑x∣y=jA[x]×B[y]=∑(x∣y)∈iA[x]×B[y]=∑x∈iA[x]×∑y∈iB[y]=FWT(A)[i]×FWT(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]​=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]=FWT(A)[i]×FWT(B)[i]​

逆变换

逆变换我们称为 IFWTIFWTIFWT,即满足 A=IFWT(FWT(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];

理性证明

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

证明: 我们现在已知 FWT(A)0,FWT(A)1FWT(A)_0,FWT(A)_1FWT(A)0​,FWT(A)1​,要求 A0,A1A_0,A_1A0​,A1​。

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

代码实现(其实和 FFTFFTFFT 很像):

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=kA[i]×B[j]C[k]=\sum\limits_{i\&j=k}A[i]\times B[j]C[k]=i&j=k∑​A[i]×B[j]。

正变换

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

这个显然也满足 FWT(A)+FWT(B)=FWT(A+B)FWT(A)+FWT(B)=FWT(A+B)FWT(A)+FWT(B)=FWT(A+B)。

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

类比或卷积,可以得到与卷积的递归公式:
FWT(A)={(FWT(A0)+FWT(A1),FWT(A1))(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)​

证明

这就不用证了吧……和或卷积基本上一毛一样,就是 A0A_0A0​ 和 A1A_1A1​ 对应位置就差一个 111,所以 A0A_0A0​ 是 A1A_1A1​ 子集,所以把 A1A_1A1​ 的贡献累加到 A0A_0A0​ 上。

求解证明

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

这里就直接贴一个数学证明了:
FWT(C)[i]=∑i∈jC[j]=∑i∈j∑x∣y=jA[x]×B[y]=∑i∈(x∣y)A[x]×B[y]=∑i∈xA[x]×∑i∈yB[y]=FWT(A)[i]×FWT(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]​=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]=FWT(A)[i]×FWT(B)[i]​

几乎就是一样的qwq

逆变换

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

证明: 我们现在已知 FWT(A)0,FWT(A)1FWT(A)_0,FWT(A)_1FWT(A)0​,FWT(A)1​,要求 A0,A1A_0,A_1A0​,A1​。

∵FWT(A)1=FWT(A1)\because FWT(A)_1=FWT(A_1)∵FWT(A)1​=FWT(A1​)
∴A1=IFWT(FWT(A1))=IFWT(FWT(A)1)\therefore A_1=IFWT(FWT(A_1))=IFWT(FWT(A)_1)∴A1​=IFWT(FWT(A1​))=IFWT(FWT(A)1​)
∵FWT(A)0=FWT(A0)+FWT(A1)\because FWT(A)_0=FWT(A_0)+FWT(A_1)∵FWT(A)0​=FWT(A0​)+FWT(A1​),即 FWT(A0)=FWT(A)1−FWT(A)0FWT(A_0)=FWT(A)_1-FWT(A)_0FWT(A0​)=FWT(A)1​−FWT(A)0​
∴A0=IFWT(FWT(A0))=IFWT(FWT(A)0−FWT(A)1)\therefore A_0=IFWT(FWT(A_0))=IFWT(FWT(A)_0-FWT(A)_1)∴A0​=IFWT(FWT(A0​))=IFWT(FWT(A)0​−FWT(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;
}

异或卷积

这个东西才是真正的 FWTFWTFWT,求法都奇奇怪怪的。

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

正变换

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

设 c(i)c(i)c(i) 表示 iii 的二进制有多少个 111,如 c(3)=2c(3)=2c(3)=2。

奇怪的定义: FWT(A)[i]=∑j=02n−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=0∑2n−1​(−1)c(i&j)A[j],也可以写成 FWT(A)[i]=(∑c(i&j)mod2=0A[j])−(∑c(i&k)mod2=1A[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=0∑​A[j])−(c(i&k)mod2=1∑​A[k])。

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

递归公式:
FWT(A)={(FWT(A0)+FWT(A1),FWT(A0)−FWT(A1))(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=0n=0n=0 时的情况~

此时要理解,求出来的 FWT(A1)FWT(A_1)FWT(A1​) 并没有考虑到他是 AAA 的右半部分,即最高位的 111 是没有考虑的,也就是说,求 FWT(A1)FWT(A_1)FWT(A1​) 时下标是 000 ~ 2n−1−12^{n-1}-12n−1−1,而不是 2n−12^{n-1}2n−1 ~ 2n−12^n-12n−1。

剩下的我们从左到右看:

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

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

求解证明

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

用数学柿子来表示的话,设 P(i)P(i)P(i) 表示 iii 的奇偶性,当 iii 是奇数时 P(i)=1P(i)=1P(i)=1,当 iii 是偶数时 P(i)=0P(i)=0P(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,ki,j,ki,j,k 的某一位,记为 x,y,zx,y,zx,y,z(注意,是同一位),那么有两种情况(已经尽力压缩了qwq,怕多了各位不看呀,下面这些看起来繁琐的东西其实逻辑很简单的,静心细看就好):

  1. x,yx,yx,y 都等于或不等于 zzz(即 x=yx=yx=y)。那么 i&ki\&ki&k 和 j&kj\&kj&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Λji\Lambda jiΛj 的这一位为 000,那么 (iΛj)&k(i\Lambda j)\&k(iΛj)&k 的这一位就是 000,对 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,yx,yx,y 一个等于 zzz,一个不等于 zzz(即 x≠yx\neq yx​=y)。假如 z=0z=0z=0,那么参照情况 111,很容易知道此时两边又是不会发生变化的。如果 z=1z=1z=1,此时 i&ki\&ki&k 和 j&kj\&kj&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Λji\Lambda jiΛj 和 kkk 的这一位同时为 111,所以 c((iΛj)&k)c((i\Lambda j)\&k)c((iΛj)&k) 会 +1+1+1,那么等式右边也会发生变化。等式两边同时变化,等式依然成立。

接下来就是求解的证明了,还是像上面那样大力展开(自己手(luan)推的,要是错了告知一下谢谢啦qwq):
FWT(C)[i]=∑j=02n−1(−1)c(i&j)C[j]=∑j=02n−1(−1)c(i&j)∑xΛy=jA[x]×B[y]=∑x=02n−1∑y=02n−1A[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=0∑2n−1​(−1)c(i&j)C[j]=j=0∑2n−1​(−1)c(i&j)xΛy=j∑​A[x]×B[y]=x=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)c(i&(xΛy))​

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

这不就是上面性质里的样子吗!于是我们可以愉快的拆开啦:
=∑x=02n−1∑y=02n−1A[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=0∑2n−1​y=0∑2n−1​A[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=02n−1∑y=02n−1A[x]×B[y]×(−1)P(c(i&x))+P(c(i&y))=∑x=02n−1∑y=02n−1A[x]×B[y]×(−1)P(c(i&x))×(−1)P(c(i&y))=∑x=02n−1A[x]×(−1)P(c(i&x))×∑y=02n−1B[y]×(−1)P(c(i&y))=FWT(A)[i]×FWT(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=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)P(c(i&x))+P(c(i&y))=x=0∑2n−1​y=0∑2n−1​A[x]×B[y]×(−1)P(c(i&x))×(−1)P(c(i&y))=x=0∑2n−1​A[x]×(−1)P(c(i&x))×y=0∑2n−1​B[y]×(−1)P(c(i&y))=FWT(A)[i]×FWT(B)[i]​

逆变换

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

设 A′=FWT(A)A'=FWT(A)A′=FWT(A),那么逆变换递推公式就是:
{(IFWT(A0′)+IFWT(A1′)2,IFWT(A0′)−IFWT(A1′)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)​

证明: 现在已知 FWT(A)0,FWT(A)1FWT(A)_0,FWT(A)_1FWT(A)0​,FWT(A)1​,求 A0,A1A_0,A_1A0​,A1​。

∵FWT(A)0=FWT(A0)+FWT(A1),FWT(A)1=FWT(A0)−FWT(A1)\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​)
∴FWT(A0)=FWT(A)0+FWT(A)12,FWT(A1)=FWT(A)0−FWT(A)12\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)0​−FWT(A)1​​
∴A0=IFWT(FWT(A0))=IFWT(FWT(A)0+FWT(A)12)\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​​)
A1=IFWT(FWT(A1))=IFWT(FWT(A)0−FWT(A)12)~~~~A_1=IFWT(FWT(A_1))=IFWT(\frac {FWT(A)_0-FWT(A)_1} 2)    A1​=IFWT(FWT(A1​))=IFWT(2FWT(A)0​−FWT(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<<18int 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);
}

快速沃尔什变换(FWT)详详详解相关推荐

  1. 解题报告(一)快速沃尔什变换FWT(ACM / OI)超高质量题解

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  2. 快速沃尔什变换(FWT)

    1前言 在之前学完了FFT稍微码了一些题.也学习了一下NTT相关的知识之后,我觉得有必要学习一下FWT,这篇博客就是阐述我对FWT的理解的 2介绍 2.1解决的问题 对于FFT,它的过程本质上是cn= ...

  3. 【learning】快速沃尔什变换FWT

    问题描述 已知\(A(x)\)和\(B(x)\),\(C[i]=\sum\limits_{j\otimes k=i}A[j]*B[k]\),求\(C\) 其中\(\otimes\)是三种位运算的其中一 ...

  4. [学习笔记]快速沃尔什变换 (FWT)

    FWT的简介 一般 FWT \text{FWT} FWT用来解决一下问题: C k = ∑ i ∣ j = k A i B j C_k=\sum_{i|j=k}A_iB_j Ck​=∑i∣j=k​Ai ...

  5. 快速沃尔什变换(FWT)及K进制异或卷积快速子集变换(FST)讲解

    前言: $FWT$是用来处理位运算(异或.与.或)卷积的一种变换.位运算卷积是什么?形如$f[i]=\sum\limits_{j\oplus k==i}^{ }g[j]*h[k]$的卷积形式(其中$\ ...

  6. 快速沃尔什变换(FWT) 学习笔记

    最近在做多校联赛的题目,发现有一道题需要用到FWT,于是我就去学了一下.膜拜一下大神,本篇博客仅对这篇博客进行一些细节上的补充. FWT要解决的问题是 Ck=∑i⊕j=kai∗bi {C}_{k}=\ ...

  7. 《小学生都能看懂的快速沃尔什变换从入门到升天教程》(FWT / FMT / FMI)(最最严谨清晰的证明!零基础也能得学会!)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 0x00 卷积 0x01 多项式 0x02 卷积的定义 0x03 卷积的基本性质 0x04 位运 ...

  8. [多项式算法](Part 4)FWT 快速沃尔什变换 学习笔记

    其他多项式算法传送门: [多项式算法](Part 1)FFT 快速傅里叶变换 学习笔记 [多项式算法](Part 2)NTT 快速数论变换 学习笔记 [多项式算法](Part 3)MTT 任意模数FF ...

  9. 快速沃尔什变换(FWT)讲解 解决集合卷积的方法

    由于某次CSDN更新,文章样式已经丢失,大量公式无法正常显示,本博客也不再维护. 请到快速沃尔什变换FWT查看,有更加完整的公式讲解. 能看到这篇博客的人,一定知道FWT是干什么的.(什么?你不知道? ...

  10. [模板] 快速沃尔什变换

    快速沃尔什变换 快速沃尔什变换是求这样的式子: 对序列 \(A\), \(B\), 求序列 \(C\), 使得 \[ C_{i}=\sum_{j \oplus k} A_{j} B_{k} \] 其中 ...

最新文章

  1. Hibernate关联关系映射
  2. Linux MySQL 忘记root 密码
  3. NLP复习资料(8)-知识图谱、信息抽取
  4. PAT 1014 Waiting in Line
  5. linux怎样卸载conda,【原创文章】生信软件环境conda的安装与卸载
  6. 在php里bd2什么意思,PSR-2 PHP三元语法中是否需要括号?
  7. 概述Swing窗体的种类
  8. Spring Cloud 子项目
  9. 二维随机变量期望公式_多维随机变量的特征数
  10. 初次项目:电子通讯录
  11. 停车场web项目(内含有数据库)
  12. 【天下有春】剑气纵横三万里,一剑光寒十九洲
  13. 2023全球边缘计算大会·北京站成功召开!
  14. C语言复数运算(结构体)
  15. linux md文件 编辑,用Vim写md文档的简单姿势
  16. 牛顿迭代法 matlab程序
  17. Spark中组件Mllib的学习16之分布式行矩阵的四种形式
  18. 深度 | Nature论文:无监督表征学习,用电子健康病历增强临床决策
  19. 当商业空间撞见元宇宙艺术
  20. MySQL数据库13——插入数据(INSERT)

热门文章

  1. this和spuer的区别
  2. Spark-Core源码学习记录 3 SparkContext、SchedulerBackend、TaskScheduler初始化及应用的注册流程
  3. ORA-01221: data file 5 is not the same file to a background process
  4. AIBlockChain:“知名博主独家讲授”人工智能创新应用竞赛【精选实战作品】之《基于计算机视觉、自然语言处理、区块链和爬虫技术的智能会议系统》软件系统案例的界面简介、功能介绍分享之四、数据挖掘
  5. 求救:varlist not allowed#stata
  6. 第七天;信息打点-资产泄漏CMS识别Git监控SVNDS_Store备份
  7. 更有效的桌面环境切换方式
  8. 【问题记录】VeeValidate配置中文的两种不同做法
  9. waitfor 的用法
  10. 计算机文件用英语怎么说,电脑里的文件是什么意思