快速沃尔什变换
解决什么问题?
回顾之前学过的快速傅里叶变换,能在 \(O(n\log n)\) 的时间复杂度内计算下面这个卷积式:
\[C[k] = \sum_{i+j=k}A[i]\times B[j]
\]
而快速沃尔什变换解决的问题与上式略有不同:
\[C[k] = \sum_{i\bigoplus j = k} A[i]\times B[j]
\]
其中,\(\bigoplus\) 表示逻辑运算符号,可以是或、与、异或。
怎么解决?
为了叙述方便,我们定义如下基于数组 \(A, B\) 的运算:
- \(A+B = \{A[0] +B[0], A[1]+B[1],\cdots \}\)
- \(A-B = \{A[0] - B[0], A[1] - B[1], \cdots \}\)
- \(A\times B = \{A[0]\times B[0], A[1]\times B[1],\cdots \}\)
- \(A \bigoplus B = \{\sum_{i\bigoplus j=0} A[i]\times B[j], \sum_{i\bigoplus j=1} A[i]\times B[j]\}\) 注意:此处为卷积操作,而上述三条为按位操作
或卷积
或卷积式最为平凡的情况,我们先从它来入手。仿照快速傅里叶变换的思路,我们需要定义一个正变换 \(FWT\) 与逆变换 \(IFWT\)(注意 \(FWT(A)\) 和 \(IFWT(A)\) 都是数组),先分别对 \(A, B\) 应用 \(FWT\),再将第 \(0 \sim 2^n -1\) 项对应相乘,即 \(FWT(A | B) = FWT(A) \times FWT(B)\),最后再对 \(FWT(A|B)\) 施加逆变换操作得到 \(A|B\)(卷积而非按位)。
怎么在或卷积中构造这样的正变换规则呢?定义 \(j \subseteq i\) 表示集合的二进制表示中 \(j\) 为 \(i\) 的子集,我们定义:
\[FWT(A)[i] = \sum_{j\subseteq i}A[j]
\]
下面来证明这样构造的正变换符合性质 \(FWT(A|B) = FWT(A)\times FWT(B)\),不妨考虑第 \(i\) 位的值:
\[\bigg(FWT(A)\times FWT(B)\bigg)[i] = FWT(A)[i]\times FWT(B)[i]=\left(\sum_{x \subseteq i} A[x]\right)\times \left(\sum_{y\subseteq i} B[y] \right)
\]
\[\begin{aligned}
FWT(A|B)[i] &= \sum_{j\subseteq i} \sum_{x|y=j} A[x]\times B[y]\\
&=\sum_{j\subseteq i}\sum_{x, y}A[x]\times B[y] \times [x|y=j]\\
&=\sum_{x, y} A[x]\times B[y]\times [x|y \subseteq i]\\
&=\sum_{x, y} A[x]\times B[y] \times [x\subseteq i]\times [y\subseteq i]\\
&=\left(\sum_{x \subseteq i} A[x]\right)\times \left(\sum_{y\subseteq i} B[y] \right)
\end{aligned}
\]
因此左边等于右边,证毕。
接下来,对于一个下标为 \(0\sim 2^n -1\) 的数组 \(A\),我们如何快速地求得正变换的结果 \(FWT(A)\) 呢?
我们学习快速傅里叶变换的思路,将数组 \(A\) 划分为左右大小均为 \(2^{n-1}\) 的两块 \(A_L\) 与 \(A_R\):
\[FWT(A)=
\begin{cases}
\text{merge}(FWT(A_L), FWT(A_L) +FWT(A_R)) & n>0\\
A &n=0
\end{cases}
\]
其中 \(\text{merge}\) 函数表示把前后两个数组顺次拼接起来。
这为什么是正确的呢?当 \(n=0\) 时数组长度为 \(1\),显然成立。而当 \(n > 0\) 时,对于左边一半,其二进制最高位(\(2^{n-1}\))为 \(0\),根据 \(FWT\) 的定义式 \(A_R\) 对这部分没有任何贡献;对于右边一半,其二进制最高位是 \(1\),于是 \(FWT\) 定义式中子集的二进制分为两种情况:最高位为 \(0\) 和最高位为 \(1\),贡献分别为 \(FWT(A_L)\) 和 \(FWT(A_R)\)
最后,我们需要考虑如何求解逆变换 \(IFWT(A)\),于我而言最直接的想法是考虑反演:
\[FWT(A)[i] = \sum_{j\subseteq i} A[j] \Leftrightarrow A[i] = \sum_{j\subseteq i} (-1)^{|i| - |j|} FWT(A)[j]
\]
其中 \(|i|\) 表示 \(i\) 在二进制下 \(1\) 的个数。我观察出该反演关系的原因是容斥原理。
下面来简单证明一下这个式子的正确性(证明过程比较套路,与其它各类反演证明方式类似,就是将一个式子代入另外一个式子中):
\[\begin{aligned}
\sum_{j\subseteq i} (-1)^{|i| - |j|} FWT(A)[j] &=\sum_{j\subseteq i} (-1)^{|i| - |j|} \sum_{x\subseteq j} A[x]\\
&= \sum_{x\subseteq i} A[x] \sum_{p=0}^{|i| - |x|} (-1)^{p} \binom{|i| -|x|}{p}\\
&= \sum_{x\subseteq i} A[x] \times [|x| = |i|]\\
&= A[i]
\end{aligned}
\]
通过反演我们就能得到逆变换的递归式:
\[IFWT(A) = \begin{cases}
\text{merge} (IFWT(A_L), -IFWT(A_L) + IFWT(A_R)) & n>0\\
A & n=0
\end{cases}
\]
为什么 \(-IFWT(A_L)\) 呢?对于右半边,必定比左半边多出二进制最高位上的一个 \(1\),这样根据反演符号改变。
与卷积
和或卷积很类似,此处我们先定义正变换规则为:
\[FWT(A)[i] = \sum_{i\subseteq j} A[j]
\]
下面还是先证明构造的正变换符合性质:\(FWT(A \& B) = FWT(A)\times FWT(B)\)
\[\bigg( FWT(A)\times FWT(B)\bigg)[i] = \left(\sum_{i\subseteq x} A[x] \right) \left(\sum_{i\subseteq y}B[y] \right)
\]
\[\begin{aligned}
FWT(A\& B)[i] &= \sum_{i\subseteq j} \sum_{x\& y=j} A[x]\times B[y]\\
&= \sum_{i\subseteq j}\sum_{x, y} A[x]\times B[y]\times [x\& y = j]\\
&= \sum_{x, y} A[x]\times B[y]\times [i\subseteq x\& y]\\
&= \sum_{x, y} A[x]\times B[y] \times [i\subseteq x]\times[i\subseteq y]\\
&= \left(\sum_{i\subseteq x} A[x] \right) \left(\sum_{i\subseteq y}B[y] \right)
\end{aligned}
\]
和或卷积类似,正变换符合递归式:
\[FWT(A) = \begin{cases}
\text{merge}(FWT(A_L) + FWT(A_R), FWT(A_R)) & n > 0\\
A &n=0
\end{cases}
\]
逆变换 \(IFWT(A)\) 也同样考虑反演:
\[FWT(A)[i] = \sum_{i\subseteq j} A[j] \Leftrightarrow A[i] = \sum_{i\subseteq j} (-1)^{|j| - |i|} FWT(A)[j]
\]
证明:
\[\begin{aligned}
\sum_{i\subseteq j} (-1)^{|j| - |i|} FWT(A)[j] &= \sum_{i\subseteq j}(-1)^{|j| - |i|}\sum_{j\subseteq x } A[x]\\
&= \sum_{i\subseteq x} A[x] \sum_{p = 0}^{|x| - |i|} (-1)^{p} \binom{|x| - |i|}{p}\\
&= \sum_{i\subseteq x} A[x] \times [|x| = |i|]\\
&= A[i]
\end{aligned}
\]
于是,逆变换符合递归式:
\[IFWT(A) = \begin{cases}
\text{merge}(IFWT(A_L) - IFWT(A_R), IFWT(A_R))&n>0 \\
A &n=0
\end{cases}
\]
异或卷积
异或卷积的正变换规则看起来很奇怪,其中 \(|i|\) 还是表示 \(i\) 二进制下 \(1\) 的个数:
\[FWT(A)[i] = \sum_{j=0}^{2^n - 1} (-1)^{|i\& j|} A[j]
\]
还是先证明一下这个构造符合性质:\(FWT(A \Lambda B) = FWT(A) \times FWT(B)\)
\[\bigg(FWT(A) \times FWT(B) \bigg)[i] = \left(\sum_{j=0}^{2^n-1}(-1)^{|i\& j|}A[j] \right)\times \left(\sum_{j=0}^{2^n - 1}(-1)^{|i\& j|}B[j] \right)
\]
\[\begin{aligned}
FWT(A\Lambda B)[i] &= \sum_{j=0}^{2^n-1} (-1)^{|i\& j|}\sum_{x, y} A[x]\times B[y] \times [x\Lambda y =j]\\
&= \sum_{x, y} A[x]\times B[y] \times (-1)^{|i\& (x\Lambda y)|}\\
&= \sum_{x, y} A[x]\times B[y] \times (-1)^{|i\& x|}\times (-1)^{|i\&y|} \\
&= \left(\sum_{j=0}^{2^n-1}(-1)^{|i\& j|}A[j] \right)\times \left(\sum_{j=0}^{2^n - 1}(-1)^{|i\& j|}B[j] \right)
\end{aligned}
\]
正变换符合递归式:
\[FWT(A)= \begin{cases}
\text{merge} (FWT(A_L) + FWT(A_R), FWT(A_L) - FWT(A_R)) &n>0\\
A &n=0
\end{cases}
\]
这边的逆变换我不太会通过反演证明,但是我们不妨换一个思路:根据正变换的递归式,我们只要逆向地还原回去,不就等同于逆变换了吗?进行一波分析:
\[FWT(A)_L = FWT(A_L) + FWT(A_R), FWT(A)_R = FWT(A_L) - FWT(A_R)\\
FWT(A_L) = \frac{FWT(A)_L + FWT(A)_R}{2},FWT(A_R) = \frac{FWT(A)_L - FWT(A)_R}2\\
\]
两边同取 \(IFWT\),可得:
\[A_L = IFWT\left (\frac{FWT(A)_L + FWT(A)_R}{2}\right), A_R =IFWT\left(\frac{FWT(A)_L - FWT(A)_R}2\right)
\]
由于逆向变换 \(IFWT\) 满足线性性,我们可以展开:
\[A_L =\frac{IFWT(FWT(A)_L) + IFWT(FWT(A)_R)}{2},A_R =\frac{IFWT(FWT(A)_L) - IFWT(FWT(A)_R)}2
\]
于是我们也可以得到逆变换的递归式
\[IFWT(A) = \begin{cases}
\text{merge} \left(\dfrac{IFWT(A_L) +IFWT(A_R)}{2}, \dfrac{IFWT(A_L) - IFWT(A_R)} {2}\right) &n>0\\
A &n=0
\end{cases}
\]