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)\)

最后拼接起来有:

\[\operatorname{FWT}(A)=[\operatorname{FWT}(A_0),\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}}\) 中已经计算,做多项式减法即可。

于是最终有:

\[\operatorname{UFWT}(A)=[\operatorname{UFWT}(A_0),\operatorname{UFWT}(A_1)-\operatorname{UFWT}(A_0)] \]

我们使用 \(O(n\log n)\) 的复杂度解决了问题。

与运算

我们让 \(A^{'}_i\) 等于所有是 \(i\) 的超集的下标 \(j\) 的系数和 \(\sum\limits_{i\subseteq j}A_j\)

同或运算考虑方法,得到正变换与逆变换法则:

\[\operatorname{FWT}(A)=[\operatorname{FWT}(A_0)+\operatorname{FWT}(A_1),\operatorname{FWT}(A_1)] \]

\[\operatorname{UFWT}(A)=[\operatorname{UFWT}(A_0)-\operatorname{UFWT}(A_1),\operatorname{UFWT}(A_1)] \]

异或运算

异或比前面两个运算稍复杂。

定义 \(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{FWT}(A)=[\operatorname{FWT}(A_0)+\operatorname{FWT}(A_1),\operatorname{FWT}(A_0)-\operatorname{FWT}(A_1)] \]

类似模仿在“或运算”那一节中的考虑方法,容易推导出 \(\operatorname{UFWT}\)

\[\operatorname{UFWT}(A)=[\dfrac{\operatorname{UFWT}(A_0)+\operatorname{UFWT}(A_1)}{2},\dfrac{\operatorname{UFWT}(A_0)-\operatorname{UFWT}(A_1)}{2}] \]

至此,异或运算已经解决。

posted @ 2025-01-31 16:01  O_v_O  阅读(29)  评论(0)    收藏  举报