LOJ6503题解

容易发现一件事,假如我有 \(n\) 张相同的牌,我把它们分成了 \(m\) 段,那么会产生 \(n-m\) 个魔术对。

有了这个就很容易了。。。假设一共有 \(m\) 种颜色,第 \(i\) 种颜色有 \(a_i\) 张被分成了 \(k_i\) 段,那么答案就是 \((\sum k_i)!\prod\frac{\binom{a_i-1}{k_i-1}}{k_i!}\),且共有 \(n-\sum k_i\) 对魔术对。

所以设 \(F_i(x)=\sum_{i=1}^{a_i}\binom{a_i-1}{i-1}\frac{x^i}{i!}\),那么答案就是 \((n-k)![x^{n-k}]\prod_{i=1}^{m}F_i(x)\)

分治乘一遍 EGF 的卷积就好了。

但是发现一件事情,分出来的段有可能会相邻。。。

考虑把相邻的情况反演掉。设 \(f[k]\) 为有已经被钦定了有 \(k\) 对魔术对的方案数(就是 \((n-k)![x^{n-k}]\prod_{i=1}^{m}F_i(x)\)),\(g[k]\) 为恰好有 \(k\) 对魔术对的方案数。

那么有:

\[\sum_{i=k}^{n-1}\binom{i}{k}g[i]=f[k] \]

\[g[k]=\sum_{i=k}^{n-1}\binom{i}{k}(-1)^{i-k}f[i] \]

#include<cstdio>
#define IMP(lim,act) for(int qwq=(lim),i=0;i^qwq;++i)act
const int M=1<<19|5,mod=998244353;
int n,m,k,a[M],fac[M],ifac[M],*T[M<<2];int buf[M<<1],*w[20];
inline int Getlen(const int&n){
	int len(0);while((1<<len)<n)++len;return len;
}
inline int Add(const int&a,const int&b){
	return a+b>=mod?a+b-mod:a+b;
}
inline int Del(const int&a,const int&b){
	return b>a?a-b+mod:a-b;
}
inline void swap(int&a,int&b){
	int c=a;a=b;b=c;
}
inline int pow(int a,int b=mod-2){
	int ans(1);for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;
}
inline int binom(const int&n,const int&m){
	return 1ll*ifac[m]*ifac[n-m]%mod*fac[n]%mod;
}
inline void init(const int&n){
	const int&m=Getlen(n);int*now=buf;w[m]=now;now+=1<<m;
	w[m][0]=1;w[m][1]=pow(3,mod-1>>m+1);for(int i=2;i^1<<m;++i)w[m][i]=1ll*w[m][i-1]*w[m][1]%mod;
	for(int k=m-1;k>=0&&(w[k]=now,now+=1<<k);--k)IMP(1<<k,w[k][i]=w[k+1][i<<1]);
	fac[0]=ifac[0]=fac[1]=ifac[1]=1;for(int i=2;i<=n;++i)ifac[i]=1ll*(mod-mod/i)*ifac[mod%i]%mod;
	for(int i=1;i<=n;++i)fac[i]=1ll*fac[i-1]*i%mod,ifac[i]=1ll*ifac[i-1]*ifac[i]%mod;
}
inline void DFT(int*f,const int&M){
	const int&n=1<<M;
	for(int len=n>>1,d=M-1;d>=0;--d,len>>=1)for(int k=0;k^n;k+=len<<1){
		int*W=w[d],*L=f+(k),*R=f+(k|len),x,y;IMP(len,(x=*L,y=*R)),*L++=Add(x,y),*R++=1ll**W++*Del(x,y)%mod;
	}
}
inline void IDFT(int*f,const int&M){
	const int&n=1<<M;
	for(int len=1,d=0;d^M;++d,len<<=1)for(int k=0;k^n;k+=len<<1){
		int*W=w[d],*L=f+(k),*R=f+(k|len),x,y;IMP(len,(x=*L,y=1ll**W++**R%mod)),*L++=Add(x,y),*R++=Del(x,y);
	}
	const int&k=pow(n);IMP(n,f[i]=1ll*f[i]*k%mod);for(int i=1;(i<<1)<n;++i)swap(f[i],f[n-i]);
}
inline void Solve(const int&u,const int&L,const int&R,int&sum){
	if(L==R){
		T[u]=new int[a[L]+1];sum+=a[L]+1;for(int i=1;i<=a[L];++i)T[u][i]=1ll*binom(a[L]-1,i-1)*ifac[i]%mod;
		T[u][0]=0;return;
	}
	static int F[M],G[M];const int&mid=L+R>>1;
	int n(0),m(0),N,len(0);Solve(u<<1,L,mid,n);Solve(u<<1|1,mid+1,R,m);T[u]=new int[N=n+m-1];sum+=N;len=Getlen(N);
	IMP(n,F[i]=T[u<<1][i]);IMP(m,G[i]=T[u<<1|1][i]);DFT(F,len);DFT(G,len);IMP(1<<len,F[i]=1ll*F[i]*G[i]%mod);
	IDFT(F,len);IMP(N,T[u][i]=F[i]);IMP(1<<len,F[i]=G[i]=0);
}
signed main(){
	int sum(0);scanf("%d%d%d",&m,&n,&k);init(n+1);n=0;for(int i=1;i<=m;++i)scanf("%d",a+i);Solve(1,1,m,n);--n;
	for(int i=k;i^n;++i)sum=(sum+1ll*(i-k&1?mod-binom(i,k):binom(i,k))*fac[n-i]%mod*T[1][n-i])%mod;printf("%d",sum);
}
posted @ 2022-07-05 14:39  Prean  阅读(36)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};