zoukankan      html  css  js  c++  java
  • 从分治乘法到快速沃尔什变换及其反演

    为了方便本文的叙述,先定义如下内容:

    (a)(b)为两个序列,那么:

    ((a,b))表示将(a)(b)简单地拼接在一起组成的序列。

    (f)是一个(n)维集合幂级数((n>0)),那么:

    (f^-)表示取所有下标的最高位为(0)的项,并忽略最高位而组成的一个(n-1)维集合幂级数(其实就是(f)的前半段)。

    类似的,(f^+)表示取所有下标的最高位为(1)的项,并忽略最高位而组成的一个(n-1)维集合幂级数。(其实就是(f)的后半段)。

    (cdot)代表点积,其形式为:

    [(fcdot g)_i=f_icdot g_i ]

    (*)代表卷积,其形式为:

    [(f*g)_i=sum_{jcirc k=i}f_jcdot g_k ]

    其中下标运算(circ)会在上下文给出(或者是普遍情况,不做要求)。

    我们先考虑如何用分治乘法解决常见的集合幂级数的卷积。

    我们考虑将待卷积的集合幂级数(f)(g)拆分成((f^-,f^+))((g^-,g^+)),那么:

    [f*g=(f^-,f^+)*(g^-,g^+) ]

    显然我们可以选择一种位运算,根据这种位运算将(f^-*g^-)(f^-*g^+)(f^+*g^-)(f^+*g^+)的贡献计算给((f*g)^-)((f*g)^+)中的某一个。

    对于集合并卷积,计算贡献的式子就是:

    [f*g=(f^-*g^-,f^-*g^++f^+*g^-+f^+*g^+) ]

    显然四个新的卷积可以直接递归计算,那么递归式便为:

    [T(n)=4T(n-1)+O(2^n) ]

    解得(T(n)=O(4^n)),直接做并没有什么用。我们来考虑减少递归的次数,我们发现:

    [f^-*g^++f^+*g^-+f^+*g^+=(f^-*g^++f^+*g^-+f^+*g^+)+f^-*g^--f^-*g^- ]

    显然等式右边的前四项是可以合并的,也就是:

    (f^-*g^++f^+*g^-+f^+*g^+=(f^-+f^+)*(g^-+g^+)-f^-*g^-)

    后面一项之前已经计算过,可以重复利用,只要多算一项即可。因此递归式为:

    [T(n)=2T(n-1)+O(2^n) ]

    解得(T(n)=O(2^nn)),复杂度非常优秀。

    现在我们来尝试从分治乘法推出其快速沃尔什变换的形式。

    考虑之前推出的式子,我们对于集合幂级数(f),我们只需要保留(f^-)(f^-+f^+)即可直接递归计算其集合并卷积。那么我们不妨先定义一个变换(f'=(f^-,f^-+f^+))

    研究一下((f*g)')的性质,得到:

    [(f*g)'=(f^-*g^-,(f^-+f^+)*(g^-+g^+)) ]

    这个式子也等价于:

    [(f*g)'^-=f'^-*g'^-,(f*g)'^+=f'^+*g'^+ ]

    我们发现做了这个变换以后,集合幂级数的前半段和后半段就没有什么关系了,可以直接分开计算。那么我们不难发现如果我们对第二维也做这样的变换,我们可以分成四段进行计算。以此类推,如果对(n)维都做这样的变换的话,计算就分开成了(2^n)个独立的部分,可以直接用点积来计算。

    因此得到集合并卷积的快速沃尔什变换:

    [FWT(f)=(FWT(f^-),FWT(f^-)+FWT(f^+)) ]

    剩下的一个问题就是做过快速沃尔什变换的(f)(g)的点积是(f*g)快速沃尔什变换后的形式,因此我们还需要考虑其逆变换。

    对于一维的变换,不难发现:

    [f=(f'^-,-f'^-+f'^+) ]

    代入证明即可。类似的,我们将这个变换应用于(n)维,得到:

    [FWT^{-1}(f)=(FWT^{-1}(f^-),-FWT^{-1}(f^-)+FWT^{-1}(f^+)) ]

    集合交卷积显然是类似的,为了完整我们也来推一遍:

    [f*g=(f^-*g^-+f^-*g^++f^+*g^-,f^+*g^+) ]

    转化为两次乘法:

    [f*g=((f^-+f^+)*(g^-+g^+)-f^+*g^+,f^+*g^+) ]

    类似的得到变换(f'=(f^-+f^+,f^+)),复合得:

    [FWT(f)=(FWT(f^-)+FWT(f^+),FWT(f^+)) ]

    类似的得到其逆变换:

    [FWT^{-1}(f)=(FWT^{-1}(f^-)-FWT^{-1}(f^+),FWT^{-1}(f^+)) ]

    下面介绍集合对称差卷积。根据对称差的定义,有:

    [f*g=(f^-*g^-+f^+*g^+,f^-*g^++f^+*g^-) ]

    对于这个形式找只计算两次乘法的形式我觉得其实挺要脑力的,不过还是可以找出来的,即:

    [f*g=(frac{(f^-+f^+)*(g^-+g^+)+(f^--f^+)*(g^--g^+)}{2},frac{(f^-+f^+)*(g^-+g^+)-(f^--f^+)*(g^--g^+)}{2}) ]

    因此对于集合幂级数(f)我们只需要知道(f^-+f^+)(f^--f^+),构造变换(f'=(f^-+f^+,f^--f^+)),同样可以将卷积分为前后两部分,因此复合这个变换得到集合对称差卷积的快速沃尔什变换:

    [FWT(f)=(FWT(f^-)+FWT(f^+),FWT(f^-)-FWT(f^+)) ]

    同时得出其逆变换:

    [FWT^{-1}(f)=(frac{FWT^{-1}(f^-)+FWT^{-1}(f^+)}{2},frac{FWT^{-1}(f^-)-FWT^{-1}(f^+)}{2}) ]

    同时可以发现集合对称差卷积要求值域有(2)的逆元。

    ( m 2019.1.1upd):这篇文章写了有段时间了,之后我似乎想到了一个更简洁的解释快速沃尔什变换的方法:将逻辑或看作取(max),那么集合并卷积就是对每一维做(max)卷积。可以推得(max)卷积的卷积变换就是前缀和,逆变换就是差分。于是只要利用卷积的复合,对每一维做前缀和以及变换完之后的差分即可。集合交卷积也是相似的。至于集合对称差卷积,由于逻辑异或可以看作是模(2)意义下的加法,于是只要对每一维做长度为(2)的循环卷积即可。

  • 相关阅读:
    批处理+7zip解压用纯数字加密的压缩包zip
    golang 读取 chrome保存的网站账号信息
    c++实现"扫描检测硬件改动"
    c++获取磁盘句柄
    golang设置title并获取窗口句柄
    golang获取文件的md5
    golang获取u盘序列号(通过读取注册表实现)
    golang从文件按行读取并输出
    golang cgo注意事项
    python调用远程chromedriver.exe、selenium抓包方法
  • 原文地址:https://www.cnblogs.com/Mr-Spade/p/9697654.html
Copyright © 2011-2022 走看看