FWT
算法简介
我们知道 FFT 可以在 \(O(n\log n)\) 的时间内求解 \(C_k=\sum\limits_{i+j=k}A_i\times B_j\)。而类似的,我们将求和符号中的加号换成其余的位运算符号,即得到了 FWT。
FWT 可以在 \(O(n\log n)\) 时间内求出:
-
\(C_k=\sum\limits_{i|j=k}A_i\times B_j\)
-
\(C_k=\sum\limits_{i\&j=k}A_i\times B_j\)
-
\(C_k=\sum\limits_{i\oplus j=k}A_i\times B_j\)
算法思路
与 FFT 相似:先对 \(A,B\) 做正变换,然后两个数组按位置做点积,最后对得到的数列做逆变换。
于是我们需要关注的点就是正变换、逆变换怎么做。
以下记序列 \(A\) 经 \(\operatorname{FWT}\) 变换后的序列为 \(A^{'}\) 或 \(\operatorname{FWT}(A)\)。
或运算
正变换
我们让 \(A^{'}_i\) 等于所有是 \(i\) 的子集的下标 \(j\) 的系数和 \(\sum\limits_{j\subseteq i}A_j\)。
考虑乘积的下标 \(k\) 有:
\(\begin{aligned}A^{'}_k\cdot B^{'}_k&=(\sum\limits_{i\subseteq k}a_i)(\sum\limits_{j\subseteq k}b_j)\\&=\sum\limits_{i\subseteq k}\sum\limits_{j\subseteq k}a_ib_j\\&=\sum\limits_{(i\cup j)\subseteq k}a_ib_j=C^{'}_k\end{aligned}\)
那么 \(\operatorname{FWT}(C)=\operatorname{FWT}(A)\cdot\operatorname{FWT}(B)\)。
如何求出序列 \(A^{'}\) 呢?如果使用暴力,复杂度 \(O(n^2)\),需要优化。
- 对于多项式计算的一个常规套路,就是考虑分治。具体来说,当 \(2\) 个区间长度为 \(\frac{n}{2}\) 的都求解出来之后,合并得到一个区间长度为 \(n\) 的答案。
我们引入多项式 \(A_0,A_1\),分别表示 \(A\) 的前一半和后一半,即下标二进制最高位分别为 \(0\) 和 \(1\) 的。
假设已经求解出了 \(\operatorname{FWT}(A_0),\operatorname{FWT}(A_1)\),那么如何合并求解 \(\operatorname{FWT}(A)\) 呢?
在递归过程中,我们眼中 \(A_0\) 和 \(A_1\) 的下标都只是 \(0\sim \dfrac{n}{2}-1\),但是将两个序列合并后,一些下标就发生变化,下面分别考虑 \(A_0\) 与 \(A_1\):
-
\(\operatorname{FWT}(A_0)\) 对应的下标没有任何变化,所以变成 \(\operatorname{FWT}(A)\),这部分对应的值也没有任何变化。即 \(\operatorname{FWT}(A)[0:\dfrac{n}{2}]=\operatorname{FWT}(A_0)\)。
-
\(\operatorname{FWT}(A_1)\) 中,对于一个二进制为
1___的下标 \(k\),它在递归时已经统计了形如1___的子集,合并后它多出了形如0___的子集需要再统计。而这个信息,在 \(\operatorname{FWT}(A_0)_{k-\frac{n}{2}}\) 位置已经计算,也就是说,在位置偏移 \(\frac{n}{2}\) 的下标,恰好就有我们要的信息,直接多项式加法即可。所以 \(\operatorname{FWT}(A)[\dfrac{n}{2}:n]=\operatorname{FWT}(A_0)+\operatorname{FWT}(A_1)\)。
最后拼接起来有:
逆变换
与正变换类似,依旧考虑分治。
现在,逆变换的含义是扣除某一个位置的子集。
分 \(A_0\) 与 \(A_1\) 考虑:
-
\(\operatorname{UFWT}(A_0)\) 的下标,显然已经完全扣除。
-
\(\operatorname{UFWT}(A_1)\) 中,对于一个二进制为
1___的下标 \(k\),它已经扣除了形如1___的子集,还剩0___的子集需要扣除。这些信息在 \(\operatorname{UFWT}(A_0)_{k-\frac{n}{2}}\) 中已经计算,做多项式减法即可。
于是最终有:
我们使用 \(O(n\log n)\) 的复杂度解决了问题。
与运算
我们让 \(A^{'}_i\) 等于所有是 \(i\) 的超集的下标 \(j\) 的系数和 \(\sum\limits_{i\subseteq j}A_j\)。
同或运算考虑方法,得到正变换与逆变换法则:
异或运算
异或比前面两个运算稍复杂。
定义 \(x\circ y=\operatorname{popcnt}(x\&y)\bmod 2\)。
可以发现,\((x\circ y)\oplus(x\circ z)=x\circ(y\oplus z)\),这个性质是 \(\operatorname{FWT}\) 构造的关键。
构造 \(A^{'}_i=\sum\limits_{i\circ j=0}A_j-\sum\limits_{i\circ j=1}A_j\)。
考虑乘积的下标 \(k\):
\(\begin{aligned}A^{'}_k\cdot B^{'}_k&=(\sum\limits_{k\circ i=0}A_i-\sum\limits_{k\circ i=1}A_i)(\sum\limits_{k\circ j=0}B_j-\sum\limits_{k\circ j=1}B_j)\\&=(\sum\limits_{k\circ i=0}\sum\limits_{k\circ j=0}A_iB_j+\sum\limits_{k\circ i=1}\sum\limits_{k\circ j=1}A_iB_j)-(\sum\limits_{k\circ i=0}\sum\limits_{k\circ j=1}A_iB_j+\sum\limits_{k\circ i=1}\sum\limits_{k\circ j=0}A_iB_j)\\&=\sum\limits_{k\circ(i\oplus j)=0}A_iB_j-\sum\limits_{k\circ(i\oplus j)=1}A_iB_j=C^{'}_k\end{aligned}\)
那么它仍然满足 \(\operatorname{FWT}(C)=\operatorname{FWT}(A)\cdot\operatorname{FWT}(B)\)。
考虑正变换:
-
\(\operatorname{FWT}(A_0)\) 中,对于一个下标 \(k\):原本的下标,最高位新增了 \(0\),因为 \(0\cap 0=0\) 所以并不会改变 \(\operatorname{popcnt}\) 的奇偶性,这部分保留。还得计算 \([n/2,n)\) 这些下标和它的关系,因为 \(0\cap 1=0\),所以也不会改变原先的奇偶性,只需要再累加上 \(\operatorname{FWT}(A_1)_{k+\frac{n}{2}}\) 即可。于是 \(\operatorname{FWT}(A)[0,n/2]=\operatorname{FWT}(A_0)+\operatorname{FWT}(A_1)\)。
-
\(\operatorname{FWT}(A_1)\) 同理。因为 \(1\cap 0=0,1\cap 1=1\),所以前半段奇偶性不变,改变后半段奇偶性。于是 \(\operatorname{FWT}(A)[n/2,n]=\operatorname{FWT}(A_0)-\operatorname{FWT}(A_1)\)。
最后拼接起来有:
类似模仿在“或运算”那一节中的考虑方法,容易推导出 \(\operatorname{UFWT}\):
至此,异或运算已经解决。

浙公网安备 33010602011771号