【模板】快速沃尔什变换(FWT)
P4717 【模板】快速沃尔什变换 (FWT)
给定长度为 \(2^n\) 两个序列 \(A,B\),设
分别当 \(\oplus\) 是 or,and,xor 时求出 \(C\)。\(n\le 17\)。
参考资料
FWT?
代码为:
inline static const void mulor(int*a,int*b,int*c,int lm){
if(!(lm/=2))return void(*c=ll(*a)**b%mod);
for(int i=0;i<lm;++i)reduce(a[i+lm]+=a[i]-mod),reduce(b[i+lm]+=b[i]-mod);
mulor(a,b,c,lm),mulor(a+lm,b+lm,c+lm,lm);
for(int i=0;i<lm;++i)reduce(c[i+lm]-=c[i]);
}
如何将“递归都改为循环”:考虑\(C\)的计算与\(A,B\)的处理是独立的。且展开之后发现循环顺序不相关,故有[2]2:
inline void get() {
for (int i = 0; i < n; i++) a[i] *= b[i];
}
inline void OR(modint *f, modint x = 1) {
for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
for (int i = 0; i < n; i += o)
for (int j = 0; j < k; j++)
f[i+j+k] += f[i+j] * x;
}
OR(a), OR(b), get(), OR(a, P - 1);
又由于,每层分治相当于沿着第\(k\)位做了个卷积[1],可以进一步简化为
void OR(int *a, bool flag) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < (1<<n); ++j) if ((j>>i&1) == 0) {
int x = a[j], y = a[j+(1<<i)];
if (flag) x = P-x;
a[j+(1<<i)] = (y+x)%P;
}
}
}
FWT
为简单起见,只尝试说明异或卷积\(\bigoplus\)。
定义\(C=A\bigoplus B\iff C_i=\sum_{j\oplus k}A_jB_k\)。若\(C\)的长度为\(2^k,k\ge1\),定义\(C_0,C_1\)分别为\(C\)的前半部分与后半部分。定义\((A,B)\)表示\(A\)与\(B\)连接在一起的序列。定义\(C=A\operatorname{op}B\iff C_i=A_i\operatorname{op} B_i\),其中\(\operatorname{op}\)为二元运算(\(+,-,\times,\div\)):
理解:分治乘法
设\(X_0=(A_0+A_1)\bigoplus(B_0+B_1),X_1=(A_0-A_1)\bigoplus(B_0-B_1)\):
则\(C_0=A_0\bigoplus B_0+A_1\bigoplus B_1=\frac{X_0+X_1}{2}, C_1=A_0\bigoplus B_1+A_1\bigoplus B_0=\frac{X_0-X_1}{2}\)。
故若需要求\(A\bigoplus B\),需要先求得\(X_0,X_1\)再合并。直接分治即可。
inline void doxor(int *a, int l, int mul = 1) {
for (int i = 0; i < l; ++i) {
int x = a[i], y = a[i+l];
a[i] = (ll)(x+y)*mul%P;
a[i+l] = (ll)(x-y+P)*mul%P;
}
}
void xor(int *a, int *b, int *c, int l) {
if (!(l>>=1)) {
c[0] = (ll)a[0]*b[0]%P;
return;
}
doxor(a, l), doxor(b, l);
xor(a, b, c), xor(a+l, b+l, c+l);
doxor(c, l, (P+1)/2);
}
理解:数学归纳法[6]6
设\(A*B\)表示\(A\)与\(B\)的某种卷积:
若存在递归定义的\(f,g\)使得对\(\forall A,B\)有\(f(A)\times f(B)=f(A*B),g(f(A))=1\),则可以用分治发求出\(A*B\)。
设函数\(f\)与\(g\)满足:
若可以递归地定义:\(\oplus\)表示某二元位运算,\(\bigoplus\)表示该位运算的卷积。
若对长为\(2^0,2^1\)的\(A,B\),有类似定义的\(f,g\)满足\(f(A)\times f(B)=f(A\bigoplus B),g(f(A))=A\),则可以证明对长度为\(2^k\)的\(A,B\),均满足\(f(A)\times f(B)=f(A\bigoplus B),g(f(A))=A\)。
若\(n=2^0\),显然有\(f(A)\times f(B)=f(A\bigoplus B)\)。
可以将 FWT 的过程看做一个线性变换的过程(左乘一个矩阵),则有\(f(A)+f(B)=f(A+B)\)。
归纳法可证明对所有\(n=2^k,C=A\bigoplus B\),有\(f(C)=f(B)\times f(A)\)。
现在只需要证明有\(g(f(A))=A\)即可。因为:
由数学归纳法即证。
理解:多维FFT
对于异或来说,可以将FWT理解成一个多维的FFT,即对于一个
来自何爷爷的讲解 ↩︎