FWT - 快速沃尔什变换

更好的阅读体验戳此进入

(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)

题外话:写 COCI 的一道题的时候发现需要用到 k 进制 FWT,然后来填 FWT 的坑,然后发现 and,or 也是 FMT,然后又发现 FMT 我也不会,于是准备在挖个坑,以后有时间也补一下 FMT ...

这里额外说一下对于多项式约定俗成的几种运算表示什么相信你们一定都知道

这里我们假设 A 最高次为 N 次,B 最高次为 M 次。

max(N,M)=P

(A,B)=(A(0),A(1),,A(N),B(0),B(1),,B(M))即拼接两个多项式A+B=(A(0)+B(0),A(1)+B(1),,A(P)+B(P))即按位相加AB=(A(0)B(0),A(1)B(1),,A(P)B(P))即按位相减AB=(A(0)B(0),A(1)B(1),,A(P)B(P))即按位相乘,注意不是卷积A×B=(i+j=0A(i)×B(j),i+j=1A(i)×B(j),,i+j=N+MA(i)×B(j))多项式卷积AB=(ij=0A(i)×B(j),ij=1A(i)×B(j),)可以理解为广义上的卷积

目的

FWT(快速沃尔什变换)一般用于处理形如如下式子的卷积:

C(x)=ij=xA(i)×B(j)

此处的 一般为 &, |, ^, 也就是 and,or,xor

思路

与大多数多项式快速变换的思路一样,我们的目的都是找到一种变换,对于 FWT 可以考虑记作:

FWT(A)

我们需要让这个变换满足以下性质:

FWT(A)FWT(B)=FWT(C)

且:

AB=C

对于不同的运算都有着与之对应的不同的变换方式,我们的目的就是要找到一种优秀的变换并快速地进行变换。

或卷积

或卷积和与卷积应该算是 FWT 和 FMT 的交集了吧,我们这里为了方便理解亦或卷积所以也要讲一下或和与卷积。

显然式子如下:

C(x)=ij=xA(i)×B(j)

或者记作:

C=A|B

一些定义

这里我们定义 FWT 正变换为:

FWT(A)(i)=jiA(j)

可以理解为下标的子集求和,而对于下标子集这个概念,也就是二进制上的子集,如 (001101)2(101101)2

定义 A0,A1 为将 A 拆成两个部分,A0 表示其前 2n1 项,而 A1 表示其后 2n1 项,这里我们也可以发现,和 FFT 一样,FWT 也需要保证 n2 的整数次幂。(注意:这里拆完之后两个多项式的下标均从 0 开始)

一些性质与证明

显然有如下性质:

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

证明也很简单,考虑将每一位分别考虑:

FWT(A)(i)=jiA(j)FWT(B)(i)=jiB(j)
FWT(A+B)(i)=ji(A+B)(j)=jiA(j)+B(j)=FWT(A)(i)+FWT(B)(i)

显然我们可以得到如下的递归式子:

FWT(A)={A(n=0)( FWT(A0),FWT(A0)+FWT(A1) )otherwise

证明:

首先明确一下,多项式的项数为 2n

n=0 时显然成立。

我们可以考虑按二进制来观察 A0A1A0 表示的是原多项式 [0,2n11] 的位置, A1 表示的是原多项式 [2n1,2n1] 的位置,如果我们按顺序考虑 A0,A1 相同位置上表示的原多项式的位置,就会发现他们在二进制表示上均互相差最高位的 1。举个例子, n=5 时:

A0:(00000)2,(00001)2,,(01111)2A1:(10000)2,(10001)2,,(11111)2

所以我们就能发现, A0 每一位都是 A1 的子集,而 A1 每一位都不是 A0 的子集。

于是显然,FWT(A0)+FWT(A1) 就是整个 FWT(A) 的右半部分,左半部分同理,得证。

还有一个性质,即我们这个变换之后的式子是可以按位乘的。

FWT(A)FWT(B)=FWT(C)

证明:

有一种感性理解的证明方法,仔细思考了一下感觉挺正确的,这里也写一下:

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

严格证明:

FWT(C)(i)=jiC(j)=jixy=jA(x)×B(y)=(xy)jA(x)×B(y)=xiA(x)×xiB(y)=FWT(A)(i)FWT(B)(i)

而对于 FWT 的逆运算,即 IFWT,仅需要把加法变成减法即可,即:

IFWT(A)={A(n=0)( IFWT(A0),IFWT(A1)IFWT(A0) )otherwise

证明很简单,根据 FWT 的性质推一下即可:

FWT(A)0=FWT(A0)A0=IFWT(FWT(A0))=IFWT(FWT(A)0)
FWT(A)1=FWT(A0)+FWT(A1)FWT(A1)=FWT(A)1FWT(A0)A1=IFWT(FWT(A1))=IFWT(FWT(A)1FWT(A)0)

Code

与卷积

和或卷积几乎一样,求的是:

C(x)=ij=xA(i)×B(j)

定义:

FWT(A)(i)=ijA(j)

有递归式子:

FWT(A)={A(n=0)( FWT(A0)+FWT(A1),FWT(A1) )otherwise
IFWT(A)={A(n=0)( IFWT(A0)IFWT(A1),IFWT(A1) )otherwise

Code:

异或卷积

异或卷积才是真正的 FWT 内容。

Tips: 这里建议如果下面的内容不太理解可以直接翻到下面,从矩阵的角度去思考,我个人感觉多项式这里如果能把矩阵理解透了,从转移矩阵去考虑,才会发现多项式美妙在哪里,而且整个推导过程很合理直观!

显然异或卷积求的式子为如下:( 即为异或,且这里表示的是二进制异或,也可以写成 2)

C(x)=ij=xA(i)×B(j)

一些“人类智慧”的定义

ci 表示 i 在二进制下 1 的数量,如 c5=c(101)2=2

然后下面这个定义特别离谱

对于异或运算,由前人的智慧我们可知有如下的 FWT 变换:

FWT(A)(i)=j=02n1(1)cijA(j)

或记作:

FWT(A)(i)=(cij mod 2=0A(j))(cik mod 2=1A(k))

看着就很离谱而且和异或没有关系,这个东西也确实很离谱,后面会进行证明。

此时我们考虑,为了更快速地算出结果,

并且有如下递归公式:

FWT(A)={A(n=0)( FWT(A0)+FWT(A1),FWT(A0)FWT(A1) )otherwise

这个看起来也很奇怪,如果实在不明白为什么会有这种思路也可以考再去看看与和或的卷积看完,难度上要比异或好理解。

一些离谱的证明

对于递推公式的证明:

首先 n=0 的情况很显然,就不证明了。

依然考虑最高位,显然对于 FWT(A)0 最高位需要为 0,而 FWT(A0) 最高位为 0,与运算的时候和 FWT(A1) 运算后也不会使最高位变成 1,所以直接相加。

对于 FWT(A)1,同样考虑对于 FWT(A1) 运算时会多一个高位的 1,从而导致 cij 多了 1,从而会多乘一个 1,故我们减去它,而 FWT(A)0 显然不会受到影响。

对于这个运算可以按位乘的证明,我认为比较离谱,如果从矩阵的角度考虑更好理解一些,所以标准的方法这里就咕掉了,具体的证明会在后文提到。

然后逆运算大概这样,和之前与和或的区别不大,同理证明。

IFWT(A)={A(n=0)( IFWT(A0)+IFWT(A1)2,IFWT(A0)IFWT(A1)2 )otherwise

Code

k 进制与卷积和或卷积

这个网上似乎没有说的,有的也只是一句话,我感性理解了一下,似乎和二进制的差不多?把包含的定义感性理解为每一位都小于,应该就可以解决了吧(这个不保证正确性,也没找到合适的例题)

upd - 然后再某篇文章里看到了这样一句话,验证了猜想的正确性。

由于 k 进制下,FMT 仍然能解决或卷积以及和卷积,因此 FWT 一般用来解决异或卷积。

k 进制异或卷积

众所周知,k 进制异或指的是,按照 k 进制每一位相加后 modk。(可以感性理解为不进位的 k 进制加法)

k 进制与运算指的是,按照 k 进制相乘后 modk,(不进位的 k 进制乘法)

k 进制与和或运算也可以理解为,按位取 minmax

k 进制的求 P(i) 指的是二进制每一位求和后 mod2

单位根?

对于二进制的异或,我们选取的底数为 1 以保证符合性质,而 k 进制显然 1 不再符合要求,然后经过人类智慧的思考,我们会发现,单位根似乎很符合这个性质,如果我们取复数的 k 次单位根,就会满足 ω0,ω1,ω2,,ωk1 各不相同且 ωi=ωimodk

然而这里我们发现对于这个东西,似乎很难理解,这里我们全部重头再来,从矩阵的角度再次思考。

再看目的与思路

如果用矩阵的角度取思考,我们可以想到,对于任意一个 FWT 变换我们可以设存在一个矩阵 T,有如下式子:

FWT(A)=TA

而我们就是要找到这样一个矩阵 T 使其符合以下运算:

TATB=TC

再看二进制异或卷积

与卷积和或卷积比较好理解就不说了,我们直接考虑异或卷积。

我们考虑令矩阵 T(i,j) 元为 ω(i,j),令多项式项数为 2n,则显然我们可以得到如下式子:

FWT(A)(x)=i=02n1ω(x,i)×A(i)

将我们的目标式子进行如下转化:

FWT(A)FWT(B)=FWT(C)FWT(A)(x)FWT(B)(x)=FWT(C)(x)i=02n1ω(x,i)×A(i)×j=02n1ω(x,j)×B(j)=k=02n1ω(x,k)×C(k)

考虑我们要构造什么?显然是要上面的式子求出满足 ij=k 的值,或者写成:

ij=kA(i)×B(j)×ω(x,i)×ω(x,j)=C(k)×ω(x,k)

观察这个式子不难看出我们要构造的矩阵需要满足:

ω(x,i)×ω(x,j)=ω(x,k)(ij=k)

这样式子就能转化为:

ij=kA(i)×B(j)=C(k)

于是发现,我们想要的最终式子出现了!

然后我们考虑如何快速求,显然与之前的思路类似,进行递归。

首先我们知道了 ω 满足异或的性质,那么显然它一定满足可以按位拆分的性质,证明比较显然,通过这个性质应该就可以理解了:

i0=i

显然按位拆分后,异或起来值不变,所以我们可以将按位拆分的式子更严谨地写成如下:

ω(i,j)=k=0ω(i2k,j2k)

进行如下定义:

定义 A0,A1 为将 A 拆成两个部分,A0 表示其前 2n1 项,而 A1 表示其后 2n1 项(注意:这里拆完之后两个多项式的下标均从 0 开始)。

定义 x 的二进制最高位为 x1,剩下的为 x0

考虑进行如下推导:

Tips: 对于这个 2n1 指的就是多项式的最高次幂,或者说项数减一,写成这个形式是因为项数需要保证为 2n 的形式,与 FFT 类似。

FWT(A)(x)=i=02n1ω(x,i)×A(i)=i=02n11ω(x,i)×A(i)+i=2n12n1ω(x,i)×A(i)=i=02n11ω(x1,0)×ω(x0,i0)×A(i)+i=2n12n1ω(x1,1)×ω(x0,i0)×A(i)=ω(x1,0)×FWT(A0)(x0)+ω(x1,1)×FWT(A1)(x0)

解释一下最后两步变换。

对于前后两部分的下标,显然前者所有项最高位一定为 0, 后者所有项最高位一定为 1,所以我们将 i 首位为 01 的情况拆开来看,对于前者不用考虑首位为 1,对于后者不用考虑首位为 0,于是即可分解成第三步的两个式子。

对于第四步,简单观察即可发现很显然,于是我们便可以将其进行递归,可以通过主定理计算复杂度:

T(n)=2T(n2)+O(n)=O(nlogn)

现在,唯一的问题就是如何构造这个矩阵 T

对于二进制下的异或,我们只需要构造一个 2×2 的矩阵,又由于我们需要进行 IFWT,所以矩阵需要有逆。

即:

[ω(0,0)ω(0,1)ω(1,0)ω(1,1)]

其需要满足以下性质:

ω(0,0)×ω(0,0)=ω(0,0)ω(0,1)×ω(0,0)=ω(0,1)ω(0,0)×ω(0,1)=ω(0,1)ω(0,1)×ω(0,1)=ω(0,0)ω(1,0)×ω(1,0)=ω(1,0)ω(1,1)×ω(1,0)=ω(1,1)ω(1,0)×ω(1,1)=ω(1,1)ω(1,1)×ω(1,1)=ω(1,0)

因为需要有逆,所以需要矩阵的秩为 2

于是可以考虑到如下矩阵:

[1111]=[12121212]1

矩阵求逆的方法这里不再赘述,到此我们就解决了 FWT 二进制异或卷积。

回到 k 进制

如果是从矩阵的角度解决二进制,我们仔细想一下就会发现,在矩阵的意义上,k 进制与二进制的思路差距很小,无非就是一些细节的改变,理解了矩阵之后便豁然开朗。

我们同样目的是构造:

TATB=TC

此时多项式项数一定为 kn 的形式。

而我们依然考虑将 ωk 进制拆开,其显然仍然符合性质,并且同样在 k 进制下拆分最高位,这里有一些细节需要注意:

定义 xk 进制最高位为 x1,剩下的为 x0

A 平均拆为 k 段,记作 A0,A1,A2,,Ak1

于是和之前思路一样,有:

FWT(A)(x)=i=0kn1ω(x,i)×A(i)=t=0k1ω(x1,t)i1=tω(x0,i0)×A(i)=t=0k1ω(x1,t)×FWT(At)(x0)

通过主定理计算时间复杂度:

T(n)=kT(nk)+O(kn)=O(nklogkn)

考虑 ω 需要符合的性质:

ω(x,i)×ω(x,j)=ω(x,m)(ikj=m)

或写成:

ω(x,i)×ω(x,j)=ω(x,m)(k | i+jm)

此时我们再考虑单位根,便可发现可以构造如下的 k×k 矩阵:

[11111ωk1ωk2ωkk11ωk2ωk4ωk2(k1)1ωkk1ω2(k1)ωk(k1)(k1)]

观察发现这个矩阵显然符合我们的要求,且我们在 FFT 的时候就用过这个矩阵,且其存在逆矩阵,为:

1k[11111ωk1ωk2ωk(k1)1ωk2ωk4ωk2(k1)1ωk(k1)ω2(k1)ωk(k1)(k1)]

然后这个矩阵似乎叫范德蒙德矩阵(不会)

至此,我们终于完成了 k 进制 FWT 的推导。

Code

Luogu 模板题

P4717 【模板】快速莫比乌斯/沃尔什变换 (FMT/FWT)

Code

k 进制 FWT 题

【清华集训2016】石家庄的工人阶级队伍比较坚强

LG-P7930 [COCI2021-2022#1] Set

嗯这道题就是梦开始的地方

写在后面

关于 FWT 仍然有很多扩展,比如在模意义下考虑单位根不存在,然后进行扩域等一系列看不懂的操作,比如这个链接

以及 k 很大的时候,如 这个链接

只能说学无止境吧,以后有时间再去研究研究。

UPD

update-2022_09_01 与和或完成

update-2022_09_02 初稿