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 ight] left[ sum_{R subseteq 2^U} (-1)^{|T cap R|}g_R ight])

如果我们做出如下定义

对于集合幂级数 (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 imes 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 imes 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("
");
	
	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("
");
	
	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("
");
	return 0;
}

原文地址:https://www.cnblogs.com/zzyer/p/9285283.html