[HDU6057]Kanade’s convolution

Kanade's convolution

題解

我們要求的式子是c_{k}=\sum_{i \& j=k}a_{i \oplus j}\cdot b_{i | j}

長得極其醜陋。。。

於是我們考慮將其變形一下,令x=i|j \, , \, y=i\oplus j,於是條件i\& j= k\Rightarrow x-y= k。因爲y有的1的位置x肯定都有,所以x-y=k\Rightarrow x\oplus y= k。由於可以構成這樣的(x,y)數對的(i,j)數對總共有2^{bit_{n}}個,我們需要在加時乘上一個2^{bit_{n}}。並且加上滿足條件[x\& y=y]

於是原式就成了

c_{k}= \sum_{x\oplus y=k} [x\&y=y]2^{bit_{y}}a_{x}b_{y}。看起來好像FWT呀,可是這個條件該怎麼做呢?

我們發現由於x,y它們之間的關係並且x\oplus y = k,故[x\&y=y]\Rightarrow bit_{x}-bit_{y}=bit_{k}。而bit_{x}bit_{y}又可以代表它裏面1的個數,我們便想到先把2^{bit_{y}}加到a_{x}中,再用FMT的形式來表示它,設a_{bit_{i}}=\left \{ a_{bit{i},i},...\right \},就成了

C_{k}=\sum_{i=k}^{n}A_{i}B_{i-k}。於是,就可以用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;
}
/*

*/

謝謝!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章