快速沃尔什变换

快速沃尔什变换核心解决的问题是, 对于两个长度为 nn、从 00 开始编号的数组 AABB, 在 O(nlogn)\mathcal{O}(n\log{n}) 的时间内求出下述定义的数组 CC

C[i]=xy=iA[x]B[y]C[i] = \sum_{x \oplus y \, = \, i}{A[x] \cdot B[y]}

其中 \oplus 为位运算 and,or,xor\operatorname{and}, \operatorname{or}, \operatorname{xor} 中的一个 ,记为

C=ABC = A * B

接下来 ++ 表示算术加法,\cdot 表示算术乘法. 如果运算符两边是数组,则表示下标对应的两项间做运算.

和 FFT 类似,为了解决这个问题,构造一个变换 F\mathcal{F} 出来使得

C=ABF{C}=F{A}F{B}C = A * B \Longleftrightarrow \mathcal{F}\{C\} = \mathcal{F}\{A\} \cdot \mathcal{F}\{B\}

同时要存在一个逆变换 F1\mathcal{F}^{-1} 使得

A=F1{F{A}}A = \mathcal{F}^{-1}\{\mathcal{F}\{A\}\}

前人已经推出了 F\mathcal{F} 是怎样一个变换. 设 A,BA, B 的长度为 2k2^k,不足 2k2^k 的部分用 00 补全. 用 A0A_0 表示 AA 的前 2k12^{k-1} 项(即下标最高位为 00 的项), A1A_1 表示 AA 的后 2k12^{k-1} 项(即下标最高位为 11 的项). [A,B][A, B] 表示 A,BA, B 拼接而成的新数组.

  • 异或

F{A}=[F{A0}+F{A1},F{A0}F{A1}]\mathcal{F}\{A\} = \left[\mathcal{F}\{A_0\}+\mathcal{F}\{A_1\}, \mathcal{F}\{A_0\}-\mathcal{F}\{A_1\}\right]

F1{A}=[F1{A0+A12},F1{A0A12}]\mathcal{F}^{-1}\{A\} = \left[ \mathcal{F}^{-1}\{\frac{A_0+A_1}{2}\}, \mathcal{F}^{-1}\{\frac{A_0-A_1}{2}\} \right]

  • 按位与

F{A}=[F{A0}+F{A1},F{A1}]\mathcal{F}\{A\} = \left[\mathcal{F}\{A_0\}+\mathcal{F}\{A_1\}, \mathcal{F}\{A_1\}\right]

F1{A}=[F1{A0}F1{A1},F1{A1}]\mathcal{F}^{-1}\{A\} = \left[ \mathcal{F}^{-1}\{A_0\}-\mathcal{F}^{-1}\{A_1\}, \mathcal{F}^{-1}\{A_1\} \right]

  • 按位或

F{A}=[F{A0},F{A1}+F{A0}]\mathcal{F}\{A\} = \left[\mathcal{F}\{A_0\}, \mathcal{F}\{A_1\}+\mathcal{F}\{A_0\}\right]

F1{A}=[F1{A0},F1{A1}F1{A0}]\mathcal{F}^{-1}\{A\} = \left[ \mathcal{F}^{-1}\{A_0\}, \mathcal{F}^{-1}\{A_1\}-\mathcal{F}^{-1}\{A_0\} \right]

模板

(待整理)

void FWT(int a[],int n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;  
                //xor:a[i+j]=x+y,a[i+j+d]=(x-y+mod)%mod;  
                //and:a[i+j]=x+y;  
                //or:a[i+j+d]=x+y;  
            }  
}

void UFWT(int a[],int n)  
{  
    for(int d=1;d<n;d<<=1)  
        for(int m=d<<1,i=0;i<n;i+=m)  
            for(int j=0;j<d;j++)  
            {  
                int x=a[i+j],y=a[i+j+d];  
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;  
                //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;  
                //and:a[i+j]=x-y;  
                //or:a[i+j+d]=y-x;  
            }  
}
void solve(int a[],int b[],int n)  
{  
    FWT(a,n);  
    FWT(b,n);  
    for(int i=0;i<n;i++) a[i]=1LL*a[i]*b[i]%mod;  
    UFWT(a,n);  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Last Updated: 8/18/2018, 2:32:44 PM