https://www.luogu.com.cn/problem/P4717
#include<bits/stdc++.h>
using namespace std; //FWT
typedef long long ll;
const int maxn=1e6+5;
const int MOD=998244353;
int n,limit;
ll a[maxn<<1],b[maxn<<1],c[maxn<<1];
ll t1[maxn<<1],t2[maxn<<1];
ll qpow(ll a,ll b)
{
ll t1=a,t2=1;
while(b)
{
if(b&1)
t2=t2*t1%MOD;
t1=t1*t1%MOD;
b>>=1;
}
return t2;
}
void FWT_or(ll *A,int inv)
{
for(int mid=1;mid<limit;mid<<=1)
{
for(int i=0;i<limit;i+=mid<<1)
{
for(int j=0;j<mid;j++)
{
if(inv==1)
A[mid+i+j]=(A[i+j]+A[mid+i+j])%MOD;
else
A[mid+i+j]=(A[mid+i+j]-A[i+j]+MOD)%MOD;
}
}
}
}
void FWT_and(ll *A,int inv)
{
for(int mid=1;mid<limit;mid<<=1)
{
for(int i=0;i<limit;i+=mid<<1)
{
for(int j=0;j<mid;j++)
{
if(inv==1)
A[i+j]=(A[i+j]+A[mid+i+j])%MOD;
else
A[i+j]=(A[i+j]-A[mid+i+j]+MOD)%MOD;
}
}
}
}
void FWT_xor(ll *A,int inv)
{
ll x,y;
ll inv2=MOD+1>>1; //因为MOD是一个质数 所以(MOD+1)/2 就是2模MOD的乘法逆元
for(int mid=1;mid<limit;mid<<=1)
{
for(int i=0;i<limit;i+=mid<<1)
{
for(int j=0;j<mid;j++)
{
x=A[i+j],y=A[mid+i+j];
A[i+j]=(x+y)%MOD;
A[mid+i+j]=(x-y+MOD)%MOD;
if(inv==-1)
{
A[i+j]=A[i+j]*inv2%MOD; // 2模MOD的乘法逆元 如果题目不是在模意义下的 除2即可
A[mid+i+j]=A[mid+i+j]*inv2%MOD;
}
}
}
}
}
int main()
{
scanf("%d",&n);
limit=1<<n; //本例题中 数组长度为 1<<n 其他情况应该补全为2^limit
for(int i=0;i<limit;i++)
scanf("%lld",&t1[i]),a[i]=t1[i];
for(int i=0;i<limit;i++)
scanf("%lld",&t2[i]),b[i]=t2[i];
FWT_or(a,1),FWT_or(b,1);
for(int i=0;i<limit;i++)
c[i]=a[i]*b[i]%MOD;
FWT_or(c,-1);
for(int i=0;i<limit;i++)
printf("%lld ",c[i]);
putchar('\n');
memcpy(a,t1,sizeof(ll)*limit);
memcpy(b,t2,sizeof(ll)*limit);
FWT_and(a,1),FWT_and(b,1);
for(int i=0;i<limit;i++)
c[i]=a[i]*b[i]%MOD;
FWT_and(c,-1);
for(int i=0;i<limit;i++)
printf("%lld ",c[i]);
putchar('\n');
memcpy(a,t1,sizeof(ll)*limit);
memcpy(b,t2,sizeof(ll)*limit);
FWT_xor(a,1),FWT_xor(b,1);
for(int i=0;i<limit;i++)
c[i]=a[i]*b[i]%MOD;
FWT_xor(c,-1);
for(int i=0;i<limit;i++)
printf("%lld ",c[i]);
putchar('\n');
return 0;
}