Luogu P4717 【模板】快速莫比乌斯/沃尔什变换 (FMT/FWT)

题链

分析

Or:

\[(x,y)->x,x+y\\ (x^2,(x+y)^2)->(x^2,2xy+y^2) \]

And:

\[(x,y)->x+y,y\\ ((x+y)^2,y^2)->(2xy+x^2,y^2) \]

Xor:

\[(x,y)->x+y,x-y\\ ((x+y)^2,(x-y)^2)->(x^2+y^2,2xy) \]

#include<bits/stdc++.h>
#define ll long long
const int p=998244353;
using namespace std;

const int N=1e6+5;
int n,a[N],b[N],inv2;
int mo(int x) {
	return x>=p?x-p:x;
}
namespace OR {
	int a[N],b[N];
	void FWT(int *a,int len,int op) {
		int L=0;
		for(;(1<<L)!=len;L++);
		for(int j=0;j<L;j++) {
			for(int i=0;i<len;i++) {
				if(!(i&(1<<j))) {
					if(op==1) a[i|(1<<j)]=mo(a[i|(1<<j)]+a[i]); 
						else a[i|(1<<j)]=mo(a[i|(1<<j)]+p-a[i]);
				}
			}
		}
	}
	void main() {
		for(int i=0;i<(1<<n);i++) {
			a[i]=::a[i],b[i]=::b[i];
		}
		FWT(a,1<<n,1),FWT(b,1<<n,1);
		for(int i=0;i<(1<<n);i++) a[i]=(ll)a[i]*b[i]%p;
		FWT(a,1<<n,-1);
		for(int i=0;i<(1<<n);i++) printf("%d ",a[i]);
		puts("");
	}
}
namespace AND {	
	int a[N],b[N];
	void FWT(int *a,int len,int op) {
		int L=0;
		for(;(1<<L)!=len;L++);
		for(int j=0;j<L;j++) {
			for(int i=0;i<len;i++) {
				if(i&(1<<j)) {
					if(op==1) a[i^(1<<j)]=mo(a[i^(1<<j)]+a[i]); 
						else a[i^(1<<j)]=mo(a[i^(1<<j)]+p-a[i]);
				}
			}
		}
	}
	void main() {
		for(int i=0;i<(1<<n);i++) {
			a[i]=::a[i],b[i]=::b[i];
		}
		FWT(a,1<<n,1),FWT(b,1<<n,1);
		for(int i=0;i<(1<<n);i++) a[i]=(ll)a[i]*b[i]%p;
		FWT(a,1<<n,-1);
		for(int i=0;i<(1<<n);i++) printf("%d ",a[i]);
		puts("");
	}
}

namespace XOR {	
	int a[N],b[N];
	void FWT(int *a,int len,int op) {
		int L=0;
		for(;(1<<L)!=len;L++);
		for(int j=0;j<L;j++) {
			for(int i=0;i<len;i++) {
				if(i&(1<<j)) {
					if(op==1) {
						int t=a[i^(1<<j)];
						a[i^(1<<j)]=mo(a[i^(1<<j)]+a[i]);
						a[i]=mo(t+p-a[i]);
					}  else {
						int t=a[i^(1<<j)];
						a[i^(1<<j)]=(ll)(a[i^(1<<j)]+a[i])*inv2%p;
						a[i]=(ll)(t+p-a[i])*inv2%p;
					}
				}
			}
		}
	}
	void main() {
		for(int i=0;i<(1<<n);i++) {
			a[i]=::a[i],b[i]=::b[i];
		}
		FWT(a,1<<n,1),FWT(b,1<<n,1);
		for(int i=0;i<(1<<n);i++) a[i]=(ll)a[i]*b[i]%p;
		FWT(a,1<<n,-1);
		for(int i=0;i<(1<<n);i++) printf("%d ",a[i]);
		puts("");
	}
}

int ksm(ll a,int b) {
	ll ret=1;
	while(b) {
		if(b&1) ret=ret*a%p;
		a=a*a%p,b>>=1;
	}
	return ret;
}
int main() {
	scanf("%d",&n);
	for(int i=0;i<(1<<n);i++) {
		scanf("%d",&a[i]);
	}
	for(int i=0;i<(1<<n);i++) {
		scanf("%d",&b[i]);
	}
	inv2=ksm(2,p-2);
	OR::main();
	AND::main();
	XOR::main();
	return 0;
}
posted @ 2021-06-08 23:26  wwwsfff  阅读(65)  评论(0编辑  收藏  举报