【FWT模板】快速沃尔什变换模板

没错,还是一个板子博客…
快速沃尔什变换。

使用方式如下:
快速沃尔什变换模板

给定长度为2n 的两个序列A,B
C [ i ] = ∑ j ⊕ k A [ j ] B [ k ] C[i] = \sum_{j\oplus k} A[j]B[k] C[i]=jkA[j]B[k]
其中 ⊕ \oplus 分别为 or,and,xor 时求出C。

FMT() 为 or
FWTand() 为 and
FWTxor() 为 xor

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
const int mod=998244353;
int n,Len;
ll A[maxn],B[maxn],C[maxn];
inline int div2(int x)	
{
	return x&1?(mod+x)/2:x/2;
}
inline void FMT(ll *a)//快速莫比乌斯变换
{
    for(int z=1;z<Len;z<<=1)
    {
    	for(int i=0;i<Len;i++) 
		{
			if(z&i) a[i] = (a[i]+a[i^z])%mod;
		}
	}
}
inline void IFMT(ll *a)//快速莫比乌斯反演
{
    for(register int z=1;z<Len;z<<=1)
    {
    	for(int i=0;i<Len;i++) 
		{
			if(z&i) a[i] = (a[i]-a[i^z]+mod)%mod;
		}
	}
}
inline void FWTand(ll *a)//快速沃尔什变换及其反演
{
    for(int i=2,ii=1;i<=Len;i<<=1,ii<<=1)
    {
    	for(int j=0;j<Len;j+=i)
    	{
    		for(int k=0;k<ii;++k)
    		{
    			a[j+k] = (a[j+k]+a[j+k+ii])%mod;
			}  
		}    
	}  
}
inline void IFWTand(ll *a)
{
    for(int i=2,ii=1;i<=Len;i<<=1,ii<<=1)
    {
    	for(int j=0;j<Len;j+=i)
    	{
    		for(int k=0;k<ii;++k)
    		{
    			a[j+k] = (a[j+k]-a[j+k+ii]+mod)%mod;
			}
		}
	}
}
inline void FWTxor(ll *a)
{
    for(int i=2,ii=1;i<=Len;i<<=1,ii<<=1)
    {
    	for(int j=0;j<Len;j+=i)
    	{
    		for(int k=0;k<ii;++k)
            {
                int t=a[j+k];
                a[j+k] = (t+a[j+k+ii])%mod;
                a[j+k+ii] = (t-a[j+k+ii]+mod)%mod;
            }
		} 
	} 
}
inline void IFWTxor(ll *a)
{
    for(int i=2,ii=1;i<=Len;i<<=1,ii<<=1)
    {
    	for(int j=0;j<Len;j+=i)
    	{
    		for(int k=0;k<ii;++k)
            {
                int t=a[j+k];
                a[j+k]=div2((t+a[j+k+ii])%mod);
                a[j+k+ii]=div2((t-a[j+k+ii]+mod)%mod);
            }
		}   
	} 
}
int main()
{
	scanf("%d",&n);
	Len = 1<<n;
	for(int i=0;i<Len;i++) scanf("%lld",A+i);
	for(int i=0;i<Len;i++) scanf("%lld",B+i);
    FMT(A);
    FMT(B);
    for(int i=0;i<Len;i++) C[i] = A[i]*B[i]%mod;
    IFMT(A);
    IFMT(B);
    IFMT(C);
    for(int i=0;i<Len;i++) printf("%d ",C[i]);
    puts("");
    FWTand(A);
    FWTand(B);
    for(int i=0;i<Len;i++) C[i] = A[i]*B[i]%mod;
    IFWTand(A);
    IFWTand(B);
    IFWTand(C);
    for(int i=0;i<Len;i++) printf("%d ",C[i]);
    puts("");
    FWTxor(A);
    FWTxor(B);
    for(int i=0;i<Len;i++) C[i] = A[i]*B[i]%mod;
    IFWTxor(C);
    for(int i=0;i<Len;i++) printf("%d ",C[i]);
    puts("");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值