FWT 学习笔记

这篇博客介绍了快速沃尔什变换(FWT)在位运算卷积中的应用,包括OR、AND和XOR三种类型。通过高维前缀和的概念,详细解释了如何利用FWT快速计算这些卷积,并提供了相应的模板代码,适用于解决相关算法问题。
摘要由CSDN通过智能技术生成

FWT 学习笔记

学的时候比较匆忙,于是就学一个 \(\texttt{or,and,xor}\) 卷积跑路。

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

前置知识:高维前缀和,下面前缀和的操作大多都是用高维前缀和来实现的。

设有两个长度为 \(2^n\) 的序列 \(A,B\),现在我们要对他们进行一下不同类型的卷积。

\(\texttt{or}\) 卷积

\[C_i=\sum_{j~\texttt{or}~k=i}A_j\times B_k \]

考虑 \(n\) 只有 \(1\) 的情况,即 \(A,B\) 的长度都只有 \(2\) 时值怎么样的:

\[C_0=A_0\times B_0\\ C_1=A_0\times B_1+A_1\times B_0+A_1\times B_1\\ C_0+C_1=(A_0+A_1)\times (B_0+B_1) \]

受到面式子的启发,考虑将 \(A,B\) 分别进行一次前缀和,每一个对应为乘起来记为 \(C\),再对 \(C\) 做一遍前缀差即可。

\(\texttt{and}\) 卷积

\[C_i=\sum_{j~\texttt{and}~k=i}A_j\times B_k \]

仍然考虑 \(n\) 只有 \(1\)

\[C_0=A_0\times B_0+A_0\times B_1+A_1\times B_0\\ C_1=A_1\times B_1\\ C_0+C_1=(A_0+A_1)\times (B_0+B_1) \]

\(A,B\) 都做一遍后缀和,按位乘起来记为 \(C\),再对 \(C\) 做一遍后缀差即可。

\(\texttt{xor}\) 卷积

\[C_i=\sum_{j~\texttt{xor}~k=i}A_j\times B_k \]

考虑 \(n\) 只有 \(1\)

\[C_0=A_0\times B_0+A_1\times B_1\\ C_1=A_0\times B_1+A_1\times B_0\\ \begin{cases} C_0+C_1=(A_0+A_1)\times (B_0+B_1)\\ C_0-C_1=(A_0-A_1)\times (B_0-B_1) \end{cases} \]

那么根据高维前缀和每一位相减过去即可。

模板题代码

// Author:A weak man named EricQian
#include<bits/stdc++.h>
using namespace std;
#define infll 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define Maxn 200005
#define mod 998244353
#define pb push_back
#define pa pair<int,int>
#define fi first
#define se second
typedef long long ll;
inline int rd()
{
	int x=0;
	char ch,t=0;
	while(!isdigit(ch = getchar())) t|=ch=='-';
	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
	return x=t?-x:x;
}
inline ll maxll(ll x,ll y){ return x>y?x:y; }
inline ll minll(ll x,ll y){ return x<y?x:y; }
inline ll absll(ll x){ return x>0ll?x:-x; }
inline ll gcd(ll x,ll y){ return (y==0)?x:gcd(y,x%y); }
struct FWT
{
	int n;
	inline int ksm(int x,int y)
	{
		int ret=1;
		for(;y;y>>=1,x=1ll*x*x%mod) if(y&1) ret=1ll*ret*x%mod;
		return ret;
	}
	inline void bitmul(int *a,int *b)
		{ for(int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%mod; }
	inline void fwt_or(int *a,int opt)
	{
		for(int p=2;p<=n;p<<=1) for(int i=0;i<n;i+=p) for(int j=0;j<(p>>1);j++)
			(a[i+j+(p>>1)]+=1ll*a[i+j]*opt%mod)%=mod;
	}
	inline void fwt_and(int *a,int opt)
	{
		for(int p=2;p<=n;p<<=1) for(int i=0;i<n;i+=p) for(int j=0;j<(p>>1);j++)
			(a[i+j]+=1ll*a[i+j+(p>>1)]*opt%mod)%=mod;
	}
	inline void fwt_xor(int *a,int opt)
	{
		for(int p=2;p<=n;p<<=1) for(int i=0;i<n;i+=p) for(int j=0;j<(p>>1);j++)
		{
			int x=a[i+j],y=a[i+j+(p>>1)];
			a[i+j]=1ll*(x+y)%mod*opt%mod;
			a[i+j+(p>>1)]=1ll*(x-y+mod)%mod*opt%mod;
		}
	}
}P;
int n,All;
int a[Maxn],b[Maxn],A[Maxn],B[Maxn];
int main()
{
	//ios::sync_with_stdio(false); cin.tie(0);
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n=rd(),All=1<<n,P.n=All;
	for(int i=0;i<All;i++) a[i]=rd();
	for(int i=0;i<All;i++) b[i]=rd();
	
	memcpy(A,a,sizeof(a)),memcpy(B,b,sizeof(b));
	P.fwt_or(A,1),P.fwt_or(B,1),P.bitmul(A,B),P.fwt_or(A,mod-1);
	for(int i=0;i<All;i++) printf("%d ",A[i]);
	printf("\n");
	
	memcpy(A,a,sizeof(a)),memcpy(B,b,sizeof(b));
	P.fwt_and(A,1),P.fwt_and(B,1),P.bitmul(A,B),P.fwt_and(A,mod-1);
	for(int i=0;i<All;i++) printf("%d ",A[i]);
	printf("\n");
	
	memcpy(A,a,sizeof(a)),memcpy(B,b,sizeof(b));
	P.fwt_xor(A,1),P.fwt_xor(B,1),P.bitmul(A,B),P.fwt_xor(A,P.ksm(2,mod-2));
	for(int i=0;i<All;i++) printf("%d ",A[i]);
	printf("\n");
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值