没错,还是一个板子博客…
快速沃尔什变换。
使用方式如下:
快速沃尔什变换模板
给定长度为2n 的两个序列A,B
C
[
i
]
=
∑
j
⊕
k
A
[
j
]
B
[
k
]
C[i] = \sum_{j\oplus k} A[j]B[k]
C[i]=∑j⊕kA[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;
}