Kanade's convolution
題解
我們要求的式子是。
長得極其醜陋。。。
於是我們考慮將其變形一下,令,於是條件。因爲y有的1的位置x肯定都有,所以。由於可以構成這樣的數對的數對總共有個,我們需要在加時乘上一個。並且加上滿足條件。
於是原式就成了
。看起來好像FWT呀,可是這個條件該怎麼做呢?
我們發現由於x,y它們之間的關係並且,故。而與又可以代表它裏面1的個數,我們便想到先把加到中,再用FMT的形式來表示它,設,就成了
。於是,就可以用FMT將其卷積後乘出來再捲回去就行了。
源碼
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<bitset>
#include<set>
using namespace std;
#define MAXN 2000005
typedef long long LL;
typedef pair<int,int> pii;
const LL mo=998244353;
const LL inv2=mo+1LL>>1LL;
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
template<typename _T>
void read2(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<1)+(s^48);s=gc();}
x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
LL n,lim,a[MAXN],b[MAXN],now,Ans,bit[MAXN];
LL f[22][MAXN],g[22][MAXN],ans[22][MAXN];
void FMT(LL *f,LL opt=1LL){
for(int k=1;k<lim;k<<=1)
for(int i=0;i<lim;i+=(k<<1))
for(int j=0;j<k;j++){
LL x=f[i+j],y=f[i+j+k];
f[i+j]=(x+y)%mo*opt%mo;
f[i+j+k]=(x-y+mo)%mo*opt%mo;
}
}
void mul(LL *A,LL *F,LL *G){for(int i=0;i<lim;i++)A[i]=(A[i]+F[i]*G[i]%mo)%mo;}
signed main(){
read(n);lim=1<<n;
for(int i=0;i<lim;i++)read(a[i]),bit[i]=bit[i>>1]+(i&1);
for(int i=0;i<lim;i++)read(b[i]);
for(int i=0;i<lim;i++)f[bit[i]][i]=a[i]*(1LL<<bit[i])%mo;
for(int i=0;i<lim;i++)g[bit[i]][i]=b[i];
for(int i=0;i<=n;i++)FMT(f[i]),FMT(g[i]);
for(int i=0;i<=n;i++)
for(int j=0;j+i<=n;j++)
mul(ans[i],f[j],g[i+j]);
for(int i=0;i<=n;i++)FMT(ans[i],inv2);now=1;
for(int i=0;i<lim;i++)Ans=(Ans+ans[bit[i]][i]*now)%mo,now=now*1526LL%mo;
printf("%lld\n",Ans);
return 0;
}
/*
*/