快速沃尔什变换也许是快速地求位运算卷积的一种方法。

给定序列 AA 和 BB ,求 CC,满足 ci=∑i=j⊕kajbkc_i=\sum\limits_{i=j\oplus k}a_jb_k,其中 ⊕\oplus 是某种运算。

与 FFT 一样, FWT 有几个流程,先将 A,BA,B 变换为 FWT⁡(A),FWT⁡(B)\operatorname{FWT}(A),\operatorname{FWT}(B),再计算 FWT⁡(C)i=FWT⁡(A)i×FWT⁡(B)i\operatorname{FWT}(C)_i=\operatorname{FWT}(A)_i\times\operatorname{FWT}(B)_i,最后将 FWT⁡(C)\operatorname{FWT}(C) 转换回 CC。

总之,是 O(nlog⁡n)O(n\log n) — O(n)O(n) — O(nlog⁡n)O(n\log n) 的三步。

FWT⁡\operatorname{FWT} 是根据不同的运算构造的。

or

即 Ci=∑i=j∣kajbkC_i=\sum\limits_{i=j|k}a_jb_k

构造 FWT⁡(A)i=∑j∣i=iaj\operatorname{FWT}(A)_i=\sum\limits_{j|i=i}a_j

这样有

FWT⁡(A)i×FWT⁡(B)i=∑j∣i=iaj×∑k∣i=ibk=∑j∣i=i,k∣i=iajbk=∑(j∣i)=iajbk=FWT⁡(C)i\begin{aligned} \operatorname{FWT}(A)_i\times\operatorname{FWT}(B)_i &=\sum\limits_{j|i=i}a_j\times\sum\limits_{k|i=i}b_k\\ &=\sum\limits_{j|i=i,k|i=i}a_jb_k\\ &=\sum\limits_{(j|i)=i}a_jb_k\\ &=\operatorname{FWT}(C)_i \end{aligned}

求 FWT⁡(A)\operatorname{FWT}(A) 的过程可以考虑递归。

设 A0,A1A_0,A_1 是AA 的前半和后半部分,则 A0A_0 与 A1A_1 只有最高位的区别,A1A_1 的子集一定包括 A0A_0 的子集。

FWT⁡(A)=merge⁡(FWT⁡(A0),FWT⁡(A0)+FWT⁡(A1))\operatorname{FWT}(A)=\operatorname{merge}(\operatorname{FWT}(A_0), \operatorname{FWT}(A_0)+\operatorname{FWT}(A_1)) ,其中 merge⁡\operatorname{merge} 是将两个序列拼接。

逆变换 IFWT⁡(A)=merge⁡(IFWT⁡(A0),IFWT⁡(A1)−IFWT⁡(A0))\operatorname{IFWT}(A)=\operatorname{merge}(\operatorname{IFWT}(A_0), \operatorname{IFWT}(A_1)-\operatorname{IFWT}(A_0))

代码

咕咕咕

and

类似地,构造 FWT⁡(A)=∑iand⁡j=iai\operatorname{FWT}(A)=\sum\limits_{i\operatorname{and}j=i}a_i。

有 FWT⁡(A)=merge⁡(FWT⁡(A0)+FWT⁡(A1),FWT⁡(A1))\operatorname{FWT}(A)=\operatorname{merge}(\operatorname{FWT}(A_0)+\operatorname{FWT}(A_1),\operatorname{FWT}(A_1))。

IFWT⁡(A)=merge⁡(IFWT⁡(A0)−IFWT⁡(A1),IFWT⁡(A1))\operatorname{IFWT}(A)=\operatorname{merge}(\operatorname{IFWT}(A_0)-\operatorname{IFWT}(A_1), \operatorname{IFWT}(A_1))

xor

重载运算符 x⊗y=(popcount⁡(xxor⁡y)) mod 2x\otimes y=(\operatorname{popcount}(x\operatorname{xor} y))\bmod 2 。

可以发现性质 没有性质我还要这运算符有何用 (x⊗y)xor⁡(x⊗z)=x⊗(yxor⁡z)(x\otimes y)\operatorname{xor}(x\otimes z)=x\otimes (y\operatorname{xor}z)

定义 FWT⁡(A)i=∑i⊗j=0aj−∑i⊗j=1aj\operatorname{FWT}(A)_i=\sum\limits_{i\otimes j=0}a_j-\sum\limits_{i\otimes j=1}a_j

然后推一推

FWT⁡(A)i×FWT⁡(B)i=(∑i⊗j=0aj−∑i⊗j=1aj)(∑i⊗k=0bk−∑i⊗k=1bk)=∑i⊗j=0aj∑i⊗k=0bk−∑i⊗j=1aj∑i⊗k=0bk−∑i⊗j=0aj∑i⊗k=0bk+∑i⊗j=1aj∑i⊗k=1bk=∑i⊗(jxor⁡k)=0ajbk−∑i⊗(jxor⁡k)=1ajbk=FWT⁡(C)i\begin{aligned} \operatorname{FWT}(A)_i\times \operatorname{FWT}(B)_i=&(\sum\limits_{i\otimes j=0}a_j-\sum\limits_{i\otimes j=1}a_j)(\sum\limits_{i\otimes k=0}b_k-\sum\limits_{i\otimes k=1}b_k)\\ =&\sum\limits_{i\otimes j=0}a_j\sum\limits_{i\otimes k=0}b_k-\sum\limits_{i\otimes j=1}a_j\sum\limits_{i\otimes k=0}b_k-\sum\limits_{i\otimes j=0}a_j\sum\limits_{i\otimes k=0}b_k+\sum\limits_{i\otimes j=1}a_j\sum\limits_{i\otimes k=1}b_k\\ =&\sum\limits_{i\otimes (j\operatorname{xor}k)=0}a_jb_k-\sum\limits_{i\otimes (j\operatorname{xor}k)=1}a_jb_k\\ =&\operatorname{FWT}(C)_i \end{aligned}

理解一下

考虑自底向上合并计算 FWT⁡\operatorname{FWT} 的过程,每次考虑的是当前长度为 2x2^x 的序列里的低 xx 位,左边的部分最高位是 00, 右边部分最高位是 11,则有公式 FWT⁡(A)=merge⁡(FWT⁡(A0)+FWT⁡(A1),FWT⁡(A0)−FWT⁡(A1))\operatorname{FWT}(A)=\operatorname{merge}(\operatorname{FWT}(A_0)+\operatorname{FWT}(A_1),\operatorname{FWT}(A_0)-\operatorname{FWT}(A_1))