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

题目

题目链接:https://www.luogu.com.cn/problem/P4717
给定长度为 \(2^n\) 两个序列 \(A,B\),设

\[C_i=\sum_{j\oplus k = i}A_j \times B_k \]

分别当 \(\oplus\) 是 or,and,xor 时求出 \(C\)

思路

弃疗了,背板。
Blog

OR 的位矩阵及其逆矩阵

\[\begin{bmatrix} 1&0 \\1 &1 \end{bmatrix}\ \ \ \begin{bmatrix}1 &0 \\-1 & 1\end{bmatrix} \]

AND 的位矩阵及其逆矩阵

\[\begin{bmatrix} 1&1 \\0 &1 \end{bmatrix}\ \ \ \begin{bmatrix}1 &-1 \\0 & 1\end{bmatrix} \]

XOR 的位矩阵及其逆矩阵

\[\begin{bmatrix} 1&1 \\1 &-1 \end{bmatrix}\ \ \ \begin{bmatrix}\frac{1}{2} &\frac{1}{2} \\\frac{1}{2} & -\frac{1}{2}\end{bmatrix} \]

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=(1<<17)+10,MOD=998244353,inv2=499122177;
const int C[7][2][2]=
{
	{{0,0},{0,0}},
	{{1,0},{1,1}},{{1,0},{MOD-1,1}},
	{{1,1},{0,1}},{{1,MOD-1},{0,1}},
	{{1,1},{1,MOD-1}},{{inv2,inv2},{inv2,MOD-inv2}}
};
int n;
ll f[N],g[N],X[N],Y[N];

void FWT(ll *f,int type)
{
	for (int k=1;k<n;k<<=1)
		for (int i=0;i<n;i+=(k<<1))
			for (int j=0;j<k;j++)
			{
				ll x=f[i+j],y=f[i+j+k];
				f[i+j]=(C[type][0][0]*x+C[type][0][1]*y)%MOD;
				f[i+j+k]=(C[type][1][0]*x+C[type][1][1]*y)%MOD;
			}
}

void Fmul(ll *f,ll *g,int type)
{
	memcpy(X,f,sizeof(X));
	memcpy(Y,g,sizeof(Y));
	FWT(X,type); FWT(Y,type);
	for (int i=0;i<n;i++) X[i]=X[i]*Y[i]%MOD;
	FWT(X,type+1);
	for (int i=0;i<n;i++) printf("%lld ",X[i]);
	printf("\n");
}

int main()
{
	scanf("%d",&n);
	n=(1<<n);
	for (int i=0;i<n;i++) scanf("%lld",&f[i]);
	for (int i=0;i<n;i++) scanf("%lld",&g[i]);
	Fmul(f,g,1); Fmul(f,g,3); Fmul(f,g,5);
	return 0;
}
posted @ 2021-01-20 15:37  stoorz  阅读(65)  评论(0编辑  收藏  举报