FWT快速沃尔什变换
基本思想
记:序列 \(a\) 经过 \(FWT\) 变换之后的序列为 \(fwt[a]\)
我们想求 \(c=a\cdot b\) ,而直接运算是 \(\mathit{O}(n^2)\) 的
若 \(a\rightarrow fwt[a]\) , \(b\rightarrow fwt[b]\) , \(fwt[c]\rightarrow c\) 是 \(\mathit{O}(n\log n)\) 的, \(fwt[c]=fwt[a]\cdot fwt[b]\) 是 \(\mathit{O}(n)\) 的
那么我们就可以 \(\mathit{O}(n\log n)\) 地求出 \(c\)
那么重中之重就在于找出 \(FWT\) 变换。
举例
在 \(OI\) 中 \(FWT\) 常常用于对下标进行位运算的卷积,即
\(\displaystyle c_i=\sum_{i=j\oplus k}a_jb_k\)
其中 \(\oplus\) 为一种二元位运算
或(or)
要求 \(\displaystyle c_i=\sum_{i=j|k}a_jb_k\)
我们可以注意到 \(j|i=i,k|i=i\rightarrow (j|k)|i=i\)
构造 \(\displaystyle fwt[a]_i=\sum_{j|i=i}a_j\)
则有
\( \begin{align*} \displaystyle fwt[a]_i \times fwt[b]_i &= \left(\sum_{j|i=i}a_j\right)\left(\sum_{k|i=i}b_k\right) \\\displaystyle&=\sum_{j|i=i}\sum_{k|i=i}a_jb_k \\\displaystyle&=\sum_{(j|k)|i=i}a_jb_k \\&=fwt[c]_i \end{align*} \)
\(a\rightarrow fwt[a]\)
要求 \(\displaystyle fwt[a]_i=\sum_{j|i=i}a_j\)
令 \(a_0\) 表示 \(a\) 中最高位为 \(0\) 的那部分序列, \(a_1\) 表示 \(a\) 中下标最高位为 \(1\) 的那部分序列。
则有
\(fwt_{or}:\begin{matrix}a_0&a_1\\\Downarrow&\Downarrow\\a_0&a_0+a_1\end{matrix}\)
于是我们可以分治求解
void OR(modint *f){
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+k]+f[i+j];
}
\(fwt[a]\rightarrow a\)
由
\(fwt_{or}:\begin{matrix}a_0&a_1\\\Downarrow&\Downarrow\\a_0&a_0+a_1\end{matrix}\)
可得
\(fwt_{or}^{-1}:\begin{matrix}a_0&a_1-a_0\\\Uparrow&\Uparrow\\a_0&a_1\end{matrix}\)
分治求解得:
void IOR(modint *f){
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+k]-f[i+j];
}
与(and)
同样的,注意到:
\(i\&j=i,i\&k=i\rightarrow i\&(j\&k)=i\)
则有 \(fwt[a]\times fwt[b]=fwt[c]\)
那么可以注意到:
\(fwt_{and}:\begin{matrix}a_0&a_1\\\Downarrow&\Downarrow\\a_0+a_1&a_0\end{matrix}\)
\(fwt_{and}^{-1}:\begin{matrix}a_0-a_1&a_1\\\Uparrow&\Uparrow\\a_0&a_1\end{matrix}\)
分治求解得:
void AND(modint *f){
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]=f[i+j]+f[i+j+k];
}
void IAND(modint *f){
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]=f[i+j]-f[i+j+k];
}
异或(xor)
这个是大头
我们已知 \(c=a\oplus b\)
对 \(a,b,c\) 进行奇偶分段
得到 \(c_0,c_1,a_0,a_1,b_0,b_1\)
显然有
\(c_0=(a_0 \oplus b_0)+(a_1 \oplus b_1)\)
\(c_1=(a_0 \oplus b_1)+(a_1 \oplus b_0)\)
考虑蝴蝶变换,其实就是分配律
\((a_0+a_1) \oplus (b_0+b_1)=(a_0 \oplus b_0)+(a_1 \oplus b_1)+(a_0 \oplus b_1)+(a_1 \oplus b_0)\)
\((a_0-a_1) \oplus (b_0-b_1)=(a_0 \oplus b_0)+(a_1 \oplus b_1)-(a_0 \oplus b_1)-(a_1 \oplus b_0)\)
则
\(fwt_{xor}:\begin{matrix}a_0&a_1\\\Downarrow&\Downarrow\\a_0+a_1&a_0-a_1\end{matrix}\)
\(fwt_{xor}^{-1}:\begin{matrix}\frac{1}2(a_0+a_1)&\frac{1}2(a_0-a_1)\\\Uparrow&\Uparrow\\a_0&a_1\end{matrix}\)
分治可得:
void XOR(modint *f,modint mul=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]=f[i+j]+f[i+j+k],
f[i+j+k]=f[i+j]-f[i+j+k]-f[i+j+k],
f[i+j]=f[i+j]*mul,
f[i+j+k]=f[i+j+k]*mul;
}
最大值(max)
定义 \(\displaystyle fwt[a]_i=\sum_{max(i,j)=i}a_j\)
又注意到: \(max(i,j)=i,max(i,k)=i\rightarrow max(max(j,k),i)=i\)
则有 \(fwt[a]\times fwt[b]=fwt[c]\)
实际上 \(\displaystyle fwt[a]_i=\sum_{max(i,j)=i}a_j=\sum_{j=1}^ia_j\)
则有:
\(fwt_{max}:\begin{matrix}a_i\\\Downarrow\\a_{i-1}+a_i\end{matrix}\)
\(fwt_{max}^{-1}:\begin{matrix}a_i-a_{i-1}\\\Uparrow\\a_i\end{matrix}\)
void MAX(modint *f){
for(int i=0;i<n;++i)f[i]=f[i]+f[i-1];
}
void IMAX(modint *f){
for(int i=0;i<n;++i)f[i]=f[i]-f[i-1];
}
居然是 \(\mathit{O}(n)\) 的,刚开始我居然没想到。