zoukankan      html  css  js  c++  java
  • 快速沃尔什变换与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)$

    [ egin{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$同理

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

    [ egin{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$需要逆变换,因此矩阵还要有逆

    [ egin{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$

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

    [ egin{bmatrix} 1& 1\ 1& -1 end{bmatrix} = egin{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_^ w(i_t, j_t)$$


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

    [ egin{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^$,那么我们取出来的实际上就是范德蒙德矩阵!

    [ egin{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} egin{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_{n - 1} w_n$

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


    感谢rqy和dkw的提示

  • 相关阅读:
    SQL语句-用sql语句得到表中所有字段的名字
    SQL语句-判断数据库中是否有这张表
    Java开发-创建第一个项目hello world
    MFC-一个很简单的程序最小化到托盘,带右键菜单带图标
    Everything SDK-基于名称快速定位文件和文件夹。
    NX二次开发-基于PycharmIDE的NXOpen Python开发环境配置
    手动局域网搭建FTP服务器
    FreeCAD二次开发-基于控制台模式FC外部开发
    FreeCAD二次开发-基于PyQT对话框与FC交互的开发
    实例开发-NX二次开发手动截图工具
  • 原文地址:https://www.cnblogs.com/reverymoon/p/10197711.html
Copyright © 2011-2022 走看看