• 「总结」多项式生成函数相关(2)


    这次主要来说一下(FWT)
    我们知道(FFT)是一种变换。
    我们要构造的(FWT)也是一种变换。

    (FWT)是用来干什么的呢?
    用来求位运算卷积。
    或许这么说还是不够明确。
    我们定义卷积是这样一个东西:

    [c_k=sumlimits_{icirc j}a_ib_j ]

    里面那个圈表示一种运算。
    普通卷积就是(+)
    狄利克雷卷积就是(*)
    子集卷积就是(subseteq)
    那么位运算卷积呢?
    (and,or,xor)

    其实(and)(or)还是比较简单的,而(xor)是最难的。

    1.(or)卷积
    我们要求这种形式的卷积:

    [c_k=sumlimits_{i or j=k}a_ib_j ]

    我们设我们的变换为(T(A)),逆变换为(IT(A))
    这个变换按照(FFT)的套路来说的话,需要满足:
    T(AB)=T(A)T(B)
    A
    B=IT(T(A)T(B))
    也就是卷积变成对位乘法。

    如果这样构造的话(其实我也不知道怎么想到这么造的):

    [T(A)_j=sumlimits_{i or j=j}A_i ]

    那么我们展开一下上面的卷积:

    [T(A*B)_i=sumlimits_{j or i=i}sumlimits_{k or l=j}A_kB_l=sumlimits_{k or lsubseteq i}A_kB_l ]

    [(T(A)T(B))_i=sumlimits_{k or i=i}A_Ksumlimits_{l or i=i}B_l=sumlimits_{k or lsubseteq i}A_kB_l ]

    所以说是对的。
    下面说怎么计算(or)卷积。
    我们考虑这个东西的转移是怎么样的。
    首先假设(A)的两半(A_0)(A_1)的变换已经计算出来了,我们现在来求(A)的变换。
    我们设(merge(A,B))为连接两个数组的函数。
    那么:

    [T(A)=merge(T(A_0),T(A_0)+T(A_1)) ]

    为什么呢?
    因为当前这一位最高位为0的情况属于为1的情况的子集,所以把(A_0)加到(A_1)那边去就可以了。
    逆变换就显然了。

    [IT(A)=merge(IT(A_0),IT(A_1)-IT(A_0)) ]

    减回去就完了。

    2.(and)卷积
    我们要求这种形式的卷积。

    [c_k=sumlimits_{i and j=k}a_ib_j ]

    同样构造变换(T)
    考虑这样的变换:

    [T(A)_i=sumlimits_{i and j=i}a_j ]

    展开一下:

    [T(A*B)_i=sumlimits_{i and j=i}sumlimits_{k and l=j}A_kB_l=sumlimits_{isubseteq k and l}A_kB_l ]

    [(T(A)T(B))_i=sumlimits_{k and i=i}sumlimits_{l and i=i}A_kB_l=sumlimits_{isubseteq k and l}A_kB_l ]

    得到了点值对乘的式子了。
    类似或卷积。

    [T(A)=merge(T(A_0)+T(A_1),T(A_1)) ]

    [IT(A)=merge(IT(A_0)-IT(A_1),IT(A_1)) ]

    3.(xor)卷积
    这里复读一下(rvalue)学长(姐)的讲解。(其实是我想不出其他的证明方法)

    对于一个二进制数(x),我们设(d(x))为其二进制(1)个数的奇偶性。
    那么有如下结论:

    [d(i and k) xor d(j and k)=d((i xor j) and k) ]

    首先(and k)相当于没有,这就是改变二进制位数的区别。
    剩下的很显然。
    (i)每次多出来一个(1),总体的(1)的奇偶性就会变化。

    尝试构造如下变换:

    [T(A)_i=sumlimits_{d(i and j)=0}A_j-sumlimits_{d(i and j)=1}A_j ]

    展开一下:

    [T(A*B)_i=left(sumlimits_{d(i and j)=0}sumlimits_{k xor l=j}A_kB_l ight)-left(sumlimits_{d(i and j)=1}sumlimits_{k xor l=j}A_kB_l ight) ]

    [egin{aligned}\ (T(A)T(B))_i&=left(sumlimits_{d(i and j)=0}A_j-sumlimits_{d(i and j)=1}A_j ight)left(sumlimits_{d(i and j)=0}B_j-sumlimits_{d(i and j)=1}B_j ight)\ &=left(sumlimits_{d(a and i) xor d(b and i)=0}A_aB_b ight)-left(sumlimits_{d(a and i) xor d(b and i)=1}A_aB_b ight)\ &=left(sumlimits_{d((a xor b) and i)=0}A_aB_b ight)-left(sumlimits_{d((a xor b) and i)=1}A_aB_b ight)\ &=left(sumlimits_{d(i and j)=0}sumlimits_{k xor l=j}A_kB_l ight)-left(sumlimits_{d(i and j)=1}sumlimits_{k xor l=j}A_kB_l ight)\ end{aligned}]

    卷积性变换构造的是对的了。
    考虑该怎么计算。

    [T(A)=merge(T(A_0)+T(A_1),T(A_0)-T(A_1)) ]

    如果最高位为0的话,那么无论如何这个(and)运算都是0,不会改变贡献。
    直接在左边即可。
    如果最高位为1的话,对于右侧的值会产生多一个1的贡献,这样会导致奇偶性取反,所以取反加上去。
    逆变换的话:

    [IT(A)=merge(frac{IT(A_0)+IT(A_1)}{2},frac{IT(A_0)-IT(A_1)}{2}) ]

    这样的话就可以快速求位运算卷积了

    现在来说一下咕了的(FMT)
    好。
    其实我们现在要求得的(FMT)和或运算卷积是一样的。
    他需要求得就是:

    [f(S)=sumlimits_{T|R=S}g(T)h(R) ]

    这个东西该怎么求呢?
    我们做一个和或运算卷积一样的东西即可了。

    [F(S)=sumlimits_{Tsubseteq S}f(T) ]

    这样和或运算的证明方式一样,这一定是对的(DFT)
    直接对位相乘即可。
    那他既然可以被或运算代替为什么还存在呢?
    (常数小码量小)
    分别考虑每一位的贡献就可以了。

    具体来说。
    我们枚举二进制位的每一位,来判断这个元素的归属。
    选或者没有选。
    那么也就是:

    [F_i[j]=F_{i-1}[j]+F_{i-1}[j-(1<<i)] ]

    这样转移就可以了。
    我们发现可以把第一维滚掉。
    这样代码就非常好写了。
    这样我们就会求(FMT)了。
    (Upd:)以上全是放屁。
    下面严谨证明:
    (G_i={1,2,...,i})
    设:

    [hat{F(S)}^{(i)}=sumlimits_{Tsubseteq S}[(S-T)subseteq G_i]f(T) ]

    初始化:$$hat{F(S)}^{(0)}=F(S)$$
    转移:
    1.(i otin S),那么(hat{F(S)}^{(i)}=hat{F(S)}^{(i-1)}),因为之前的均不含({i})
    2.(iin S),那么(hat{F(S)}^{(i)}=hat{F(S)}^{(i-1)}+hat{F(S-i)}^{(i-1)}),前者(T)中一定不含有({i}),而后者(T)中一定含有({i})
    这样迭代(n)次就可以了。
    最终求得的(hat{F}=FMT(F))

    那么怎么求(IFMT)呢?

    我们知道:

    [F(S)=sumlimits_{Tsubseteq S}f(T) ]

    子集反演得:

    [f(S)=sumlimits_{Tsubseteq S}(-1)^{|S|-|T|}F(T) ]

    这样直接就把加号写成减号就可以了。因为多一个元素那么答案整体上会乘一个-1。

    下面的才是重点。
    (FMT)求子集卷积(其实也可以(FWT)
    也就是这样的式子:

    [f(S)=sumlimits_{Tsubseteq S}h(T)g(S-T) ]

    要求更加严格了,不可以有交集。
    那么:

    [f(S)=sumlimits_{Tsubseteq S,Rsubseteq S}[|T|+|R|=|S|][T|R=S]h(T)g(R) ]

    这样就简单了。
    我们按照集合大小将这个东西分成(n)种。
    也就是:

    [F_i(S)=sumlimits_{Tsubseteq S}[|T|=i]f(T) ]

    这样还是可以用:
    (H_{i}(T))(G_{n-i}(R))来做或卷积了。
    这样复杂度变成了:
    (O(n^22^n))

  • 相关阅读:
    银行存钱取钱余额的图形程序
    centos7 的httpd的问题
    idea创建springboot项目初始化失败解决方案
    Spring Boot之yaml配置注入基本使用
    idea修改Java注释的颜色
    IDEA常用快捷键及修改快捷键
    WordPress Markdown编辑器插件:WP Githuber MD
    Docker安装solo博客部署到云服务器教程
    Spring Boot 定制个性 banner
    Java类型转换
  • 原文地址:https://www.cnblogs.com/Lrefrain/p/12025227.html
Copyright © 2020-2023  润新知