AtCoder Grand Contest 038 E - Gachapon 題解

傳送門
題目大意:
有一個隨機數生成器會隨機生成[1,N][1,N]的一個整數,第ii個數被生成的概率是AijAj\frac{A_i}{\sum_{j} A_j},每次調用這個生成器生成一個數,把生成的數排成一個序列,當對於每個數ii都出現了不少於BiB_i次時停止,求序列的期望長度。
Ai400,Bi400\sum A_i \le 400, \sum B_i \le 400
做法:
官方題解的做法過於神仙,這裏給出一種爆推生成函數的做法。
定義ai=AijAja_i=\frac{A_i}{\sum_{j} A_j},pip_i表示在第ii步內結束的概率,P(x)P(x)pp序列的指數型生成函數,即P(x)=pixii!P(x)=\sum p_i\frac{x^i}{i!}
顯然有P(x)=i(jBi(aix)jj!)=i(eaixj<Bi(aix)jj!)P(x)=\prod_i (\sum_{j \ge B_i}\frac{(a_ix)^j}{j!})=\prod_i (e^{a_ix}-\sum_{j <B_i}\frac{(a_ix)^j}{j!})
暴力展開可以化爲P(x)=ijci,jxiejxP(x)=\sum_i\sum_jc_{i,j}x^ie^{jx}其中ci,jc_{i,j}是係數
最後的答案的形式是n=0[xnn!](exP(x))\sum_{n=0}^{\infty}[\frac{x^n}{n!}](e^x-P(x))
我們發現exP(x)e^x-P(x)所有與ee相關的項ee的指數都小於11,所以這個生成函數是收斂的,可以計算它的係數和。
單獨考慮其中的一項
n=0[xnn!](xsetj)=n=0(n+s)sjn\sum_{n=0}^{\infty}[\frac{x^n}{n!}](x^se^{tj})=\sum_{n=0}^{\infty}(n+s)^{\underline{s}}j^n
暴力展開(n+s)s(n+s)^{\underline{s}},現在的問題就變成了給定ss,求n=0nsjn\sum_{n=0}^{\infty}n^sj^n
F(s)=n=0nsjnF(s)=\sum_{n=0}^{\infty}n^sj^n,FF可以通過差分遞推求得。
至此整個問題就解決了。
每一步的時間複雜度都是O((Ai)3)O((\sum A_i)^3)的(假定Ai\sum A_iBi\sum B_i同階)
代碼:

#include<bits/stdc++.h>
#define LL long long
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
using namespace std;
inline int read(){
	int v=0,f=1;
	char c=getchar();
	while (c<'0' || c>'9'){
		if (c=='-') f=-1;
		c=getchar();
	}
	while (c>='0' && c<='9'){
		v=v*10+c-'0';
		c=getchar();
	}
	return v*f;
}
const LL mod=998244353;
const int Maxn=405;
int n,a[Maxn],b[Maxn];
LL p[Maxn],pw[Maxn][Maxn];
LL fact[Maxn],ivf[Maxn];
LL qp(LL x,LL p){
	LL ret=1;
	while (p){
		if (p&1) ret=ret*x%mod;
		x=x*x%mod;
		p>>=1;
	}
	return ret;
}
LL inv(LL x){
	return qp(x,mod-2);
}
LL dp[Maxn][Maxn][Maxn],S[Maxn];
LL _coef[Maxn][Maxn],tmp[Maxn][Maxn],C[Maxn][Maxn];
void Add(LL &x,LL y){
	x+=y;
	if (x>=mod) x-=mod;
}
void _init(){
	fact[0]=1;
	for (int i=1;i<Maxn;i++){
		fact[i]=fact[i-1]*i%mod;
	}
	for (int i=0;i<Maxn;i++) ivf[i]=inv(fact[i]);
	for (int i=0;i<Maxn;i++){
		for (int j=0;j<=i;j++){
			C[i][j]=fact[i]*ivf[j]%mod*ivf[i-j]%mod;
		}
	}
	_coef[0][0]=1;
	for (int j=1;j<Maxn;j++){
		for (int k=0;k<Maxn;k++){
			_coef[j][k]=_coef[j-1][k]*j%mod;
			if (k) Add(_coef[j][k],_coef[j-1][k-1]%mod);
		}
	}
}
int main(){
	_init();
	scanf("%d",&n);
	int sa=0;
	for (int i=1;i<=n;i++) scanf("%d %d",&a[i],&b[i]),sa+=a[i];
	for (int i=1;i<=n;i++) p[i]=1ll*a[i]*inv(sa)%mod;
	for (int i=1;i<=n;i++){
		pw[i][0]=1;
		for (int j=1;j<Maxn;j++){
			pw[i][j]=pw[i][j-1]*p[i]%mod;
		}
	}
	dp[0][0][0]=1;
	for (int i=1;i<=n;i++){
		for (int j=0;j<=400;j++){
			for (int k=0;k<=sa;k++){
				
				if (k>=a[i]){
					Add(dp[i][j][k],dp[i-1][j][k-a[i]]);
				}
				for (int l=0;l<b[i];l++){
					if(j>=l) Add(dp[i][j][k],(mod-pw[i][l]*ivf[l]%mod)*dp[i-1][j-l][k]%mod);
				}
			}
		}
	}
	LL ans=0;
	for (int k=0;k<sa;k++){
		LL v=1ll*k*inv(sa)%mod;
		S[0]=inv((1-v+mod)%mod);
		LL t=S[0];
		for (int i=1;i<Maxn;i++){
			S[i]=0;
			for (int l=0;l<i;l++){
				LL coef=(i-l)&1?(1):(mod-1);
				coef=coef*C[i][l]%mod;
				if (l)S[i]+=coef*S[l];
				else S[i]+=coef*(S[l]-1);
				S[i]%=mod;
			}
			if (S[i]<0) S[i]+=mod;
			S[i]=S[i]*t%mod;
		}
		for (int j=0;j<=400;j++){
			if (dp[n][j][k]){
				LL c=mod-dp[n][j][k];
				if (k==0){
					ans+=c*fact[j];ans%=mod;
					continue;
				}
				LL res=0;
				for (int k=0;k<Maxn;k++){
					if (_coef[j][k]!=0){
						res+=_coef[j][k]*S[k];
						res%=mod;
					}
				}
				ans+=c*res;
				ans%=mod;
			}
		}
	}
	printf("%lld\n",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章