FWT 从入门到想死
位运算卷积。纯答辩。
高维前缀和
本质上是 OR 卷积。
https://www.cnblogs.com/heyuhhh/p/11585358.html
这个写得挺好。我觉得应该还算是很好理解吧?
位运算卷积
快速沃尔什变换 (FWT)
令 \(C_i=\sum\limits_{j\oplus k}A_jB_k\),则 \(C\) 是 \(A,B\) 的位运算 \(\oplus\) 的卷积。
我们希望对 \(A,B,C\) 进行 FWT 取得 \(f(A),f(B),f(C)\),然后点积计算 \(f(C)=f(A)\cdot f(B)\),再对 \(f(C)\) 进行一次 IFWT 取得 \(C\) 以控制时间复杂度。
考虑构造 FWT 的变换方案。令 \(c(i,j)\) 表示 \(A_j\) 对 \(f(A)_ i\) 的贡献系数那么有 \(f(A)_ i=\sum\limits_ {i=0}^{n-1} c(i,j)A_j\)。当然绝大多数 FWT 题都满足 \(n\) 是 \(2\) 的幂次,否则不方便我们之后的操作。不过如果真的 \(n\neq 2^k\),其实在后面补足 \(0\) 就行了。
然后进行一个狠狠的等价变换:
对左边根据定义式进行一个代换:\(C_ i=\sum\limits_{p\oplus q=i} A_pB_q\),那么有 \(f(C)_ i=\sum\limits_{j=0}^{n-1} c(i,j)\sum\limits_{p\oplus q=j} A_pB_q\)。
回代,等价变换。鉴于 \(n\) 总是等于 \(2^k\),可以再更换枚举方式:
统一字母,发现得到关系 \(c(i,j)c(i,k)=c(j\oplus k)\)。利用真值表和高中数学抽象函数求值的方法可以取得 \(c([0,1],[0,1])\) 也就是 \(c\) 函数的位矩阵。
为了方便之后分治卷积的操作并满足上述关系,我们考虑强行构造让 \(c(i,j)\) 的每一位都独立开,令 \(i_t\) 表示 \(i\) 二进制下第 \(t\) 位,\(j_t\) 表示 \(j\) 二进制下第 \(t\) 位,我们使 \(c(i,j)=\prod c(i_t,j_t)\)。回代可以发现,由于位矩阵早已满足关系,所以对于每个 \(t\) 都有 \(c(i_t,j_t)c(i_t,k_t)=c(i_t,j_t\oplus k_t)\),再把每一位合并在一起从而得到与 \(c(i,j)c(i,k)=c(i,j\oplus k)\) 等价。
假设我们已经取得了所有 \(c\),下一步就是猛算 \(f(A)_i=\sum\limits_{j=0}^{n-1} c(i,j)A_j\),当然这还是 \(\mathcal O(n^2)\) 的。
鉴于 \(n\) 总是等于 \(2^k\),考虑按二进制下最高位的值分治,再利用 \(c\) 每一位的独立性拆分进行变换:
很明显这里问题规模减半了,内部和式可以分治下去求。
考虑 \(A_0\) 表示前半部分的 \(A_j\) 组成的数列,\(A_1\) 表示后半部分的 \(A_j\) 组成的数列(注意下标从 \(0\) 而不是 \(\frac{n}{2}\) 开始),那么分类之后有:
- \(i_0=0\Rightarrow i'=i\),因为前半部分有最高位等于 \(0\),后半部分最高位等于 \(1\) 但下标改变于是 \(j'=j\Rightarrow f(A)_ i=c(0,0)f(A_0)_ i+c(0,1)f(A_1)_ i\)。
- \(i_0=1\Rightarrow i'=i-\frac{n}{2}\),同上有 \(f(A)_ {i+\frac{n}{2}}=c(1,0)f(A_0)_ i+c(1,1)f(A_1)_ i\)。
显然,\(i\in[0,\frac{n}{2})\)。显然可以使用 \(\mathcal O(n)\) 的代价合并两个问题,于是做到 \(\mathcal O(n\log n)\)。分治边界处取 \(f(A)_ i=A_i\)。
求出 \(f(A)\) 和 \(f(B)\) 后进行点积得到 \(f(C)\)。
接下来考虑 IFWT,把 \(f(C)\) 反演回去。
快速沃尔什逆变换 (IFWT)
对位矩阵 \(c\) 进行肉眼矩阵求逆,得到一个新的位矩阵,这个矩阵就是 IFWT 的分治系数,其他部分与 FWT 没有区别。这也在构造的时候提出了严苛的要求:矩阵必须要有逆。一个有逆的矩阵需要满足不存在某一行或某一列全是 \(0\),万金油的构造(指 \(\left [ \begin{matrix} 1 & 1 \\ 1 & 1\\ \end{matrix} \right ]\))其实也是没有逆的。
肉眼矩阵求逆可以从 \(0\) 的位置入手,必要时可能需要列出方程。
对 \(f(C)\) 进行 IFWT 后得到的就是 \(C\) 的原数组了。
两条性质
FWT 本质上是线性变换,所以有 \(f(A+B)=f(A)+f(B)\) 和 \(f(cA)=cf(A)\)(这里是点积)。