FWT——学习笔记

来源:互联网 发布:怎么做淘宝 编辑:程序博客网 时间:2024/06/08 03:36

什么是FWT?

我们知道普通的卷积是这样的:

Ci=j+k=iAjBk

我们用FFT可以加速这一过程。
现在我们把+ 改成某位运算,成了位运算的卷积:
Ci=jk=iAjBk

FWT就是用于解决这种卷积的。

具体思想

考虑一个变换:

DWT(A)i=j=0n1Ajf(i,j)

如果我们能找到这样一个变化系数f(i,j),使得
DWT(A)iDWT(B)i=DWT(C)i(CAB),
就能类似FFT一样,先转换,再乘,再逆转换。关键在f(i,j)如何构造。
带入一下,上面那个条件其实就等价于:f(i,j)f(i,k)=f(i,jk)

直接给出构造:
⊕为与:f(i,j)=[i&j=i]
⊕为或:f(i,j)=[i&j=j]
⊕为异或:f(i,j)=(1)cnt(i&j) (count(x)x1)
并不知道是怎么来的,但是容易验证是对的。

这些构造都有一个重要的性质,二进制每位都是独立的,可以拆开:
f(i,j)=f(i1,j1)f(i2,j2)...f(ik,jk)
下面我们就要考虑如何快速变换了,先将n补到2的次幂,每次把数列分成两半:

DWT(A)i=j=0n1Ajf(i,j)

=j=0n/21Ajf(i,j)+j=n/2n1Ajf(i,j)

=j=0n/21Ajf(i0,j0)f(i1,j1)+j=n/2n1Ajf(i0,j0)f(i1,j1)

=f(i0,0)j=0n/21Ajf(i1,j1)+f(i0,1)j=n/2n1Ajf(i1,j1)

=f(i0,0)DWT(A[0])i1+f(i0,1)DWT(A[1])i1

是不是和FFT很像啊,核心就是:
DWT(A)i=f(0,0)DWT(A[0])i+f(0,1)DWT(A[1])i
DWT(A)i+n/2=f(1,0)DWT(A[0])i+f(1,1)DWT(A[1])i
(i=0...n/21)
递归求解,可以做到O(nlogn)
关于逆转换,其实很简单,直接把之前的过程反着执行一遍即可,相当于解一个二元一次方程。

下面是模板:

#include<cstdio>#include<algorithm>using namespace std;void FWT(int a[],int n,int _k){        for(int m=2;m<=n;m<<=1)      for(int i=0;i<=n-1;i+=m)          for(int j=0;j<=m/2-1;j++){        int t0=a[i+j], t1=a[i+j+m/2];            if(_k==1){            //xor:a[i+j]=t0+t1,a[i+j+m/2]=(t0-t1+mod)%mod;                //and:a[i+j]=t0+t1;                //or:a[i+j+m/2]=t0+t1;           } else{            //xor:a[i+j]=(t0+t1)/2,a[i+j+m/2]=(t0-t1)/2;                //and:a[i+j]=t0-t1;                //or:a[i+j+m/2]=t1-t0;        }    } }    int main(){    freopen("fwt.in","r",stdin);    freopen("fwt.out","w",stdout);    return 0; }
原创粉丝点击