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)\) 的,刚开始我居然没想到。

posted @ 2024-11-28 10:54  Xie2Yue  阅读(14)  评论(0)    收藏  举报