FWT

FWT 快速沃尔什变换

一种以 \(O(n \times 2^n)\) 的时间复杂度快速计算位运算卷积的算法。

位运算卷积

分三种。

  • OR 卷积(并集卷积)

\[c_k = \sum_{i \mid j=k} a_i \cdot b_j \]

正变换即 SOS dp,逆变换即逆向 SOS dp。

证明:

\[\text{FWT\_OR}(a)[k] \times \text{FWT\_OR}(b)[k] \\ = \sum_{s \subset k} a_s \sum_{t \subset k} b_t \\ = \sum_{s \subset k} \sum_{t \subset k} a_s \cdot b_t \\ = \sum_{s \cup t \subset k} a_s \cdot b_t \\ = \sum_{u \subset k} \sum_{s \cup t=u} a_s \cdot b_t \\ = \sum_{u \subset k} c_u \\ = \text{FWT\_OR}(c)[k] \]

  • AND 卷积(交集卷积)

\[c_k = \sum_{i \& j = k} a_i \cdot b_j \]

正变换即超集 SOS dp,逆变换即逆向超集 SOS dp,证明同上。

  • XOR 卷积

\[c_k = \sum_{i \oplus j=k} a_i \cdot b_j \]

这个东西不好直接 dp 求解,提供一种分治的思路。

设数组长度为 \(2^n\),考虑最高位的情况:

  1. \(a_0\):下标 \(0 \sim 2^{n-1}-1\),对应最高位为 \(0\)

  2. \(a_1\):下标 \(2^{n-1} \sim 2^{n}-1\),对应最高位为 \(1\)

对于 \(b,c\) 数组,我们同样做类似的划分。

以上是正变换。

考虑计算 \(c\)

  1. 对于 \(c_0\),显然 \(a,b\) 最高位相同,有 \(c_0 = a_0 * b_0 + a_1 * b_1\)\(*\) 表示去掉最高位之后做卷积)

  2. 对于 \(c_1\),同理有 \(c_1 = a_0 * b_1 + a_1 * b_0\)

这个东西不好直接点乘计算,考虑构造。

具体的,我们构造 \(A_0=a_0+a_1,A_1=a_0-a_1\)\(b\) 同理),则有:

\[A_0 B_0 \\ = a_0 b_0 + a_0 b_1 + a_1 b_0 + a_1 b_1 \\ = (a_0 b_0 + a_1 b_1) + (a_0 b_1 + a_1 b_0) \\ = c_0 + c_1 \]

同理,\(A_1 B_1 = c_0 - c_1\),然后解方程即可得 \(c_0,c_1\)

以上是逆变换。

例题选讲

  • CF662C(简化问题的策略、紧扣所求

我们发现行很小,考虑状压列,记为 \(j\)

我们不妨先考虑行的反转操作,记行的操作为 \(mask\),则当前列的状态应为 \(j \oplus mask\)。对于这个状态,它最小的一的个数显然就是 \(\min(bit,n-bit)\)\(bit\) 为该状态在二进制下 \(1\) 的个数),因为可以对列再翻转一次,将这个值记为 \(val_{j \oplus mask}\)

然后问题转化为求 \(ans_{mask} = \sum val_{j \oplus mask} \cdot cnt_{j}\)\(cnt_j\) 表示状态为 \(j\) 的列数),这不就是 XOR 卷积吗?直接 FWT 解决即可。

  • P1539(OR 卷积优化状压 dp

很容易直接枚举当前行和上一行的状态然后转移,这是 \(O(n \cdot 4^n)\) 的,显然无法通过。

然后我们发现当前行某一位填 \(0\) 时上一行随意,但是这一位填 \(1\) 时上一行就只能填 \(0\),说明上一行的状态是这一行补集的子集,这显然可以 OR 卷积(或者说 SOS dp)去优化之。

注意讨论一下 \(n,m\) 的大小关系,以便矩阵进行转置。

总结

FWT 一般用途:优化状压 dp、凑成特定形式快速计算答案。

posted @ 2026-08-30 16:55  _KidA  阅读(7)  评论(0)    收藏  举报