• FWT-快速沃尔什变换


    FWT-快速沃尔什变换

    FWT有啥用啊

    我们知道,FFT可以解决多项式的卷积,即

    [C_k=sum_{i+j=k}A_i*B_j ]

    如果将操作符换一下,换成集合运算符

    比如

    [C_k=sum_{i|j=k}A_i*B_j\C_k=sum_{i&j=k}A_i*B_j\C_k=sum_{ioplus j=k}A_i*B_j ]

    这时就不能使用FFT

    但是FFT使我们产生了一种想法

    我们能不能用一种类似FFT的方法,用另一个多项式来表示(A,B),然后再对应相乘,最后再变换回来呢

    答案是可以的,这就是FWT,即快速沃尔什变换

    咋搞啊

    我们以或运算举例:

    我们按照定义,显然可以构造 (FWT[A] = A' = sum_{i=i|j}A_{j}) ,来表示 (j) 满足二进制中 (1)(i) 的子集。

    那么显然会有 (C_{i} = sum_{i=j|k}A_{j}*B_{k} Rightarrow FWT[C] = FWT[A] * FWT[B])

    至于上面这个是怎么来的:

    [egin{aligned} FWT[C][i]&=FWT[A][i]*FWT[B][i]\ sum_{j|i}C_j&=(sum_{j|i}A_j)*(sum_{j|i}B_j) \ sum_{j|i}C_j&=sum_{j|i,k|i} A_jB_k\ sum_{j|i}C_j&=sum_{j|i}sum_{a|b=j}A_aB_b\ C_j&=sum_{a|b=j}A_aB_b end{aligned} ]

    这样就和上面我们想要的式子一样了。

    一堆定义/结论

    别问我怎么推的,我也不知道。

    这里有详细的证明。

    通用性质

    性质1:

    [FWT(Apm B)=FWT(A)pm FWT(B) ]

    性质2:

    定义(oplus)为任意集合运算

    [FWT(Aoplus B)=FWT(A)*FWT(B) (对应相乘) ]

    或运算

    定义:

    [FWT(A)[i]=sum_{j|i=i}A_j ]

    正向运算:

    [FWT(A)=egin{cases}(FWT(A_0),FWT(A_1)+FWT(A_0))& n>1\ A & n=0end{cases} ]

    逆向运算:

    [IFWT(A)=egin{cases}(IFWT(A_0),IFWT(A_1)-IFWT(A_0))&n>1\ A&n=0end{cases} ]

    与运算

    定义:

    [FWT(A)[i]=sum_{i&j=j}A_i ]

    正向运算:

    [FWT(A)=egin{cases}(FWT(A_0)+FWT(A_1),FWT(A_1))&n>1\ A &n=0end{cases} ]

    逆向运算:

    [IFWT(A)=egin{cases}(IFWT(A_0)-IFWT(A_1),IFWT(A_1))&n>1\ A&n=0end{cases} ]

    异或运算

    定义:

    (d(x))(x)在二进制下拥有的1的数量

    [FWT(A)[i]=sum_{d(j&i)为偶数}A_j-sum_{d(k&i)为奇数}A_k ]

    正向运算:

    [FWT(A)=egin{cases}(FWT(A_0)+FWT(A_1),FWT(A_0)-FWT(A_1))&n>0\ A&n=0end{cases} ]

    逆向运算:

    [IFWT(A)=egin{cases}(frac{IFWT(A_0+A_1)}{2},frac{IFWT(A_0-A_1)}{2})&n>1\ A&n=0end{cases} ]

    板子

    1. 按位或
    2. 按位与
    3. 按位异或
    //by Harry_bh
    void FWT1(long long a[],int len)
    {
    	for(int mid=2;mid<=len;mid<<=1)
    	for(int i=0;i<len;i+=mid)
    	for(int j=i;j<i+(mid>>1);j++)a[j+(mid>>1)]+=a[j];
    }
    void IFWT1(long long a[],int len)
    {
    	for(int mid=2;mid<=len;mid<<=1)
    	for(int i=0;i<len;i+=mid)
    	for(int j=i;j<i+(mid>>1);j++)a[j+(mid>>1)]-=a[j];
    }
    void FWT2(long long a[],int len)
    {
    	for(int mid=2;mid<=len;mid<<=1)
    	for(int i=0;i<len;i+=mid)
    	for(int j=i;j<i+(mid>>1);j++)a[j]+=a[j+(mid>>1)];
    }
    void IFWT2(long long a[],int len)
    {
    	for(int mid=2;mid<=len;mid<<=1)
    	for(int i=0;i<len;i+=mid)
    	for(int j=i;j<i+(mid>>1);j++)a[j]-=a[j+(mid>>1)];
    }
    void FWT3(long long a[],int len)
    {
    	for(int mid=2;mid<=len;mid<<=1)
    	for(int i=0;i<len;i+=mid)
    	for(int j=i;j<i+(mid>>1);j++)
    	{
    		long long x=a[j],y=a[j+(mid>>1)];
    		a[j]=x+y,a[j+(mid>>1)]=x-y;
    	}
    }
    inline void IFWT3(long long a[],int len)
    {
    	for(int mid=2;mid<=len;mid<<=1)
    	for(int i=0;i<len;i+=mid)
    	for(int j=i;j<i+(mid>>1);j++)
    	{
    		long long x=a[j],y=a[j+(mid>>1)];
    		a[j]=(x+y)>>1,a[j+(mid>>1)]=(x-y)>>1;
    	}
    }
    

    参考资料

    LSJ-FWT

    OI-WIKI

  • 相关阅读:
    [转]lftp的致命错误:证书验证:不信任
    github每次push都需要密码以及用户名的解决办法
    Fedora最小化安装后没有ifconfig命令
    [转载]MySql常用命令总结
    chrome浏览器强制采用https加密链接
    红帽系列linux自行配置本地yum源
    linux 下dd命令直接清除分区表(不用再fdisk一个一个的删除啦)
    linux分区工具fdisk的使用
    Java多线程实现......(1,继承Thread类)
    第一篇文章--我为什么要写博客?
  • 原文地址:https://www.cnblogs.com/GavinZheng/p/11721127.html
Copyright © 2020-2023  润新知