FWT学习笔记

快速沃尔什变换学习笔记

(如果写错了请纠正)(表达不到位请多多包涵)


\(or\)

\(f[i][x]\)表示第\(i+1\)位到第\(n\)位相同,第\(1\)位到第\(i\)位是\(x\)的子集的\(a[y]\)的和

于是FMT后的数组就是 \(f[n][x]\)

考虑如何计算\(f[i][x]\)

如果\(x\)的第\(i\)位是\(0\),那么\(f[i][x]=f[i-1][x]\)

如果是\(1\),那么\(f[i][x]=f[i-1][x]+f[i-1][x-2^{i-1}]\)

用滚动数组优化可以做到空间复杂度\(O(n)\)

对于第\(i\)层来说,相当于把整个序列分成了\(2^{n-i}\)

每一段中的第\(i+1\)位到第\(n\)位相同,且每段左半段第\(i\)位是\(0\),右半段第\(i\)位是\(1\),相当于左半段对右半段对应的位置产生了贡献

代码就很容易写出来了(_)

FMT的逆变换

与正变换类似,\(f[i][x]\)表示第\(i+1\)位到第\(n\)位是\(x\)的子集,且第\(1\)位到第\(i\)位相等的\(a[y]\)的和

如果\(x\)的第\(i\)位是\(0\),那么\(f[i][x]=f[i-1][x]\)

如果是\(1\),那么\(f[i][x]=f[i-1][x]-f[i-1][x-2^{i-1}]\)

是不是很简单(_)


\(and\)

\(or\)的本质相同


\(xor\)

这个就比较难了

也叫集合的对称差卷积

定义 \(h=f \cdot g\)

\(h_S= \sum_{L \subseteq 2^U}\sum_{R \subseteq 2^U}[L \oplus R=S]f_Lg_R\)

首先注意到对于集合 \(S\)

\(\frac{1}{2^n}\sum_{T \subseteq 2^U} (-1)^{|S \cap T|} = [ S= \varnothing ]\)

这样

\(h_S= \sum_{L \subseteq 2^U}\sum_{R \subseteq 2^U}[L \oplus R \oplus S = \varnothing]f_L g_R\)

\(=\sum_{L \subseteq 2^U}\sum_{R \subseteq 2^U} \frac{1}{2^n} \sum_{T \subseteq 2^U}(-1)^{|T \cap (L \oplus R \oplus S)|}f_Lg_R\)

\(=\sum_{L \subseteq 2^U}\sum_{R \subseteq 2^U} \frac{1}{2^n} \sum_{T \subseteq 2^U}(-1)^{|T \cap L|}(-1)^{|T \cap R|}(-1)^{|T \cap S|}f_Lg_R\)

\(=\frac{1}{2^n}\sum_{T \subseteq 2^U} (-1)^{|T \cap S |} \left[ \sum_{L \subseteq 2^U} (-1)^{|T \cap L|}f_L \right] \left[ \sum_{R \subseteq 2^U} (-1)^{|T \cap R|}g_R \right]\)

如果我们做出如下定义

对于集合幂级数 \(f\) 我们定义他的快速沃尔什变换为 \(\hat f\)

\(\hat {f_S} = \sum_{T \subseteq 2^U} f_T(-1)^{|S \cap T|}\)

那么 \(\hat{f}\)的逆变换 \(f\)

\(f_S =\frac{1}{2^n} \sum_{T \subseteq 2^U} \hat{f_S} (-1)^{|S \cap T|}\)

那么我们就有

\(h_S=\frac{1}{2^n}\sum_{T \subseteq 2^U} \hat{f_T} \hat{g_T}\)

所以就有 \(\hat{f_S}\hat{g_S}=\hat{h_S}\)

这样就会得到\(h_S=\frac{1}{2^n}\sum_{T \subseteq 2^U} \hat{h_S}\)

所以现在的问题是怎么求 \(f\) 以及 \(\hat{f}\)

同样还是 DP

\(f[i][x]\)表示第 \(i+1\) 到第 \(n\) 位相同,且对\((-1)\)的指数贡献不考虑第 \(i+1\) 到第 \(n\)\((-1)^k \times a[y]\) 的和

对于第 \(i\) 层来说

如果第 \(i\) 位是 \(0\) , 那么 \(f[i][x]=f[i-1][x]+f[i-1][x+2^{i-1}]\)

如果第 \(i\) 位是 \(1\) , 那么 \(f[i][x]=f[i-1][x-2^{i-1}]-f[i-1][x]\)

对于第\(i\)层的每一段,令 \(t1=f[i-1][x],t2=f[i-1][x+2^{i-1}]\)

那么 \(f[i][x]=t1+t2\)

\(f[i][x+2^{i-1}]=t1-t2\)

对于逆变换则把它倒回去就可以了

\(f[i][x]\)表示 \(1\)\(i\)位相等,对指数贡献为 \((i+1)\)位到\(n\)位的\((-1)^k \times a[y]\)的和

如果第 \(i\) 位是 \(0\) , 那么 \(f[i][x]=\frac{f[i-1][x]+f[i-1][x+2^{i-1}]}{2}\)

如果第 \(i\) 位是 \(1\) , 那么 \(f[i][x]=\frac{f[i-1][x-2^{i-1}]-f[i-1][x]}{2}\)


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int mm=998244353;
const int maxn=1000000;
const int inv2=499122177;

int n;
long long A[maxn];
long long B[maxn];
long long C[maxn];

void FMTor(long long *arr,int n,int f){
	for(int k=1;k<n;k<<=1){
		int p=k+k;
		for(int i=0;i<n;i+=p){
			for(int j=0;j<k;++j){
				if(f==1){
					arr[i+j+k]=(arr[i+j+k]+arr[i+j])%mm;
				}else{
					arr[i+j+k]=(arr[i+j+k]-arr[i+j]+mm)%mm;
				}
			}
		}
	}
}
void FMTand(long long *arr,int n,int f){
	for(int k=1;k<n;k<<=1){
		int p=k+k;
		for(int i=0;i<n;i+=p){
			for(int j=0;j<k;++j){
				if(f==1){
					arr[i+j]=(arr[i+j]+arr[i+j+k])%mm;
				}else{
					arr[i+j]=(arr[i+j]-arr[i+j+k]+mm)%mm;
				}
			}
		}
	}
}

void FWTxor(long long *arr,int n,int f){
	for(int k=1;k<n;k<<=1){
		int p=k+k;
		for(int i=0;i<n;i+=p){
			for(int j=0;j<k;++j){
				long long x=arr[i+j],y=arr[i+j+k];
				if(f==1){
					arr[i+j]=(x+y)%mm;
					arr[i+j+k]=(x-y+mm)%mm;
				}else{
					arr[i+j]=(x+y)*inv2%mm;
					arr[i+j+k]=(x-y+mm)*inv2%mm;
				}
			}
		}
	}
}

int main(){
	scanf("%d",&n);
	for(int i=0;i<(1<<n);++i)scanf("%lld",&A[i]);
	for(int i=0;i<(1<<n);++i)scanf("%lld",&B[i]);
	
	FMTor(A,1<<n,1);
	FMTor(B,1<<n,1);
	for(int i=0;i<(1<<n);++i)C[i]=A[i]*B[i]%mm;
	FMTor(A,1<<n,-1);
	FMTor(B,1<<n,-1);
	FMTor(C,1<<n,-1);
	for(int i=0;i<(1<<n);++i)printf("%lld ",C[i]);
	printf("\n");
	
	FMTand(A,1<<n,1);
	FMTand(B,1<<n,1);
	for(int i=0;i<(1<<n);++i)C[i]=A[i]*B[i]%mm;
	FMTand(A,1<<n,-1);
	FMTand(B,1<<n,-1);
	FMTand(C,1<<n,-1);
	for(int i=0;i<(1<<n);++i)printf("%lld ",C[i]);
	printf("\n");
	
	FWTxor(A,1<<n,1);
	FWTxor(B,1<<n,1);
	for(int i=0;i<(1<<n);++i)C[i]=A[i]*B[i]%mm;
	FWTxor(A,1<<n,-1);
	FWTxor(B,1<<n,-1);
	FWTxor(C,1<<n,-1);
	for(int i=0;i<(1<<n);++i)printf("%lld ",C[i]);
	printf("\n");
	return 0;
}

posted @ 2018-07-09 18:34  ws_zzy  阅读(200)  评论(2编辑  收藏  举报