快速沃尔什变换与k进制FWT


这是一篇用来卖萌的文章QAQ


考虑以下三类卷积

\(C_k = \sum \limits_{i \;or\;j = k} A_i * B_j\)

\(C_k = \sum \limits_{i\;and\;j = k} A_i * B_j\)

\(C_k = \sum \limits_{i\;xor\;j = k}A_i * B_j\)

由于前两种可以用FMT(高维前缀和)解决,那我们就谈谈第三种吧

下文中的\(n\)都是形如\(2^i - 1\)的数

下标的开与闭是根据好不好写来定的,但是还是可以意会的...


虽然有人知道为什么了,但是我还是不知道为什么要这么做

我们尝试寻找一个矩阵\(T\),其\((i, j)\)元为\(w(i, j)\),使得

\[TA \cdot TB = TC \]

我们不妨记\(TA = fwt(A)\)

自然的,\(fwt(A)[x] = \sum \limits_{i = 0}^n w(x, i) * A_i\)

那么,等式两边同时展开,我们可以得到

\[fwt(A)[x] \cdot fwt(B)[x] = fwt(C)[x] \]

\[\sum \limits_{i = 0}^n w(x, i) * A_i \sum \limits_{j = 0}^n w(x, j) * B_j = \sum \limits_{k = 0}^n w(x, k) * C_k \]

对比两边\(C_k\)的表达式, 我们自然希望这个变换满足

\[\sum \limits_{i \oplus j = k} A_i * B_j * w(x, i) * w(x, j) = C_k * w(x, k) \]

如果有\(w(x, i) * w(x, j) = w(x, k) \;(i \oplus j = k)\),那么我们就能得到\(\sum \limits_{i \oplus j = k} A_i * B_j = C_k\)

这不就是我们想要的式子嘛....,

那我就构造一个满足\(w(x, i) * w(x, j) = w(x, k) \;(i \oplus j = k)\)\(T\)矩阵


不仅如此,我们还需要可以快速地计算出\(fwt(A)\)

\[\begin{aligned} fwt(A)[i] &= \sum \limits_{k = 0}^n w(i, k) A_k \\ &= \sum \limits_{k = 0}^{n / 2} w(i, k) w(i, 0) A_k + \sum \limits_{k = n / 2}^n w(i, k) w(i, n / 2)\\ \end{aligned} \]

不难注意到,前半部分已经成为了一个子问题,然而后半部分还没有

我们希望通过\(w\)的某些性质,能够使得右边成为一个子问题

联想到\(w\)需要满足异或的性质,因此,我们不妨让\(w\)拥有可以按位拆分的性质

\[w(i, j) = \prod_{k = 0}^{...} w(i\;\&\;2^k, j \;\&\;2^k) \]

下面的化式子来源于rqy神仙

如果有上面的性质,我们记\(i\)的二进制的最高位为\(i_1\),其他位为\(i_0\)\(k\)同理

那么,原本的式子可以转化成

\[\begin{aligned} fwt(A)[i] &= \sum \limits_{k = 0}^{n / 2} w(i_1, 0) w(i_0, k_0) A_k + \sum \limits_{k = n / 2}^n w(i_1, 1) w(i_0, k_0) A_k \\ &= w(i_1, 0) fwt(A_0)[i_0] + w(i_1, 1) fwt(A_1)[i_0]\\ \end{aligned} \]

应该看得出\(A_0\)\(A_1\)是什么吧...

复杂度为\(T(n) = 2T(n / 2) + O(n) = O(n \log n)\)


那么,考虑构造\(w\),其实只要构造一个\(2 * 2\)的矩阵,由于\(C\)需要逆变换,因此矩阵还要有逆

\[\begin{bmatrix} w(0, 0) & w(0,1)\\ w(1,0)& w(1,1) \end{bmatrix} \]

根据上面的异或性质,我们有

\[w(0, 0) * w(0, 0) = w(0, 0) \;\;\;\;...(1)\\ w(0, 1) * w(0, 0) = w(0, 1) \;\;\;\;...(2)\\ w(0, 1) * w(0, 1) = w(0, 1) \;\;\;\;...(3)\\ w(1, 0) * w(1, 1) = w(1, 1) \;\;\;\;...(4)\\ w(1, 1) * w(1, 1) = w(1, 0)\;\;\;\; ...(5)\\ w(1, 0) * w(1, 0) = w(1, 0) \;\;\;\;... (6) \]

注意到矩阵要有逆,因此秩需要为\(2\)

然后就可以弄出这么一个矩阵

\[\begin{bmatrix} 1& 1\\ 1& -1 \end{bmatrix} = \begin{bmatrix} 0.5& 0.5\\ 0.5& -0.5\\ \end{bmatrix}^{-1} \]

然后代进程序即可


\(k\)进制\(FWT\)


计算\(C_k = \sum \limits_{i \oplus j = k} A_i * B_j\)

由于\(K\)进制下,FMT仍然能解决或卷积以及和卷积,因此FWT一般用来解决异或卷积

在下文中,\(n = K^i - 1\)

自然地,还是希望构造\(TA \cdot TB = TC\)

还是一样的展开

\[fwt(A)[x] \cdot fwt(B)[x] = fwt(C)[x] \]

\[\sum \limits_{i = 0}^n w(x, i) * A_i \sum \limits_{j = 0}^n w(x, j) * B_j = \sum \limits_{k = 0}^n w(x, k) * C_k \]

还是一样的对比系数,然后我们能够得出,当\(w(x, i) * w(x, j) = w(x, k) \;(i \oplus j = k)\)时,这样子做的正确性有保证

并且,同样的,不妨设\(i = (i_0 i_1 i_2 ... i_m)_k\)

那么,我们构造$$w(i, j) = \prod \limits_{t = 0}^{m} w(i_t, j_t)$$


我们根据\(i\)\(k\)进制下的最高位来讨论,我们记一个数\(x\)\(k\)进制下的最高位为\(x'\),其余位为\(x''\)

\[\begin{aligned} fwt(A)[i] &= \sum \limits_{t = 0}^n w(i, t) A_t \\ &= \sum \limits_{t = 0}^{k - 1} w(i', t) \sum \limits_{x' = t} w(i'', x'') A_x \\ &= \sum \limits_{t = 0}^{k - 1} w(i', t) fwt(A_t)[i''] \end{aligned} \]

复杂度是\(T(n) = kT(n / K) + O(Kn) = O(nK \log_K n)\)\(n\)\(K\)的幂)


我们需要考虑\(K * K\)\(T\)矩阵是什么

由于\(w(x, i) * w(x, j) = w(x, k) (i \oplus j = k)\),也就是\(w(x, i) * w(x, j) = w(x, k) ([K | i + j - k])\)

注意到单位根在复平面意义下有循环的意义

因此,我们尝试取\(w(x, i) = w_k^{xi}\),那么我们取出来的实际上就是范德蒙德矩阵!

\[\begin{bmatrix} 1& 1 & 1& ... & 1\\ 1& w_k^1& w_k^2& ... & w_k^{k - 1}\\ 1& w_k^2 & w_k^4& ... & w_k^{2(k - 1)}\\ ...& ...& ...& ...& ...\\ 1& w_k^{k - 1}& w_k^{2(k - 1)} & ... & w_k^{(k - 1)(k - 1)} \end{bmatrix} \]

由于范德蒙德卷积的行列式为\(\prod \limits_{i < j} (x_i - x_j)\),在这个单位根矩阵中,不存在两两相等的数

因此这个有逆,事实上, 在FFT中,我们早已经见过这个矩阵的逆矩阵了,它是

\[\frac{1}{k} \begin{bmatrix} 1& 1 & 1& ... & 1\\ 1& w_k^{-1}& w_k^{-2}& ... & w_k^{-(k - 1)}\\ 1& w_k^{-2} & w_k^{-4}& ... & w_k^{-2(k - 1)}\\ ...& ...& ...& ...& ...\\ 1& w_k^{-(k - 1)}& w_k^{-2(k - 1)} & ... & w_k^{-(k - 1)(k - 1)} \end{bmatrix} \]

原因是\([n | t] = \sum \limits_{i = 0}^{n - 1} w_n^{ti}\)

这样,我们就可以成功的计算出k进制FWT啦!


感谢rqy和dkw的提示