AtCoder Grand Contest 038 E - Gachapon 题解

传送门
题目大意:
有一个随机数生成器会随机生成 [ 1 , N ] [1,N] [1,N]的一个整数,第 i i i个数被生成的概率是 A i ∑ j A j \frac{A_i}{\sum_{j} A_j} jAjAi,每次调用这个生成器生成一个数,把生成的数排成一个序列,当对于每个数 i i i都出现了不少于 B i B_i Bi次时停止,求序列的期望长度。
∑ A i ≤ 400 , ∑ B i ≤ 400 \sum A_i \le 400, \sum B_i \le 400 Ai400,Bi400
做法:
官方题解的做法过于神仙,这里给出一种爆推生成函数的做法。
定义 a i = A i ∑ j A j a_i=\frac{A_i}{\sum_{j} A_j} ai=jAjAi, p i p_i pi表示在第 i i i步内结束的概率, P ( x ) P(x) P(x) p p p序列的指数型生成函数,即 P ( x ) = ∑ p i x i i ! P(x)=\sum p_i\frac{x^i}{i!} P(x)=pii!xi
显然有 P ( x ) = ∏ i ( ∑ j ≥ B i ( a i x ) j j ! ) = ∏ i ( e a i x − ∑ j < B i ( a i x ) j j ! ) 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)=i(jBij!(aix)j)=i(eaixj<Bij!(aix)j)
暴力展开可以化为 P ( x ) = ∑ i ∑ j c i , j x i e j x P(x)=\sum_i\sum_jc_{i,j}x^ie^{jx} P(x)=ijci,jxiejx其中 c i , j c_{i,j} ci,j是系数
最后的答案的形式是 ∑ n = 0 ∞ [ x n n ! ] ( e x − P ( x ) ) \sum_{n=0}^{\infty}[\frac{x^n}{n!}](e^x-P(x)) n=0[n!xn](exP(x))
我们发现 e x − P ( x ) e^x-P(x) exP(x)所有与 e e e相关的项 e e e的指数都小于 1 1 1,所以这个生成函数是收敛的,可以计算它的系数和。
单独考虑其中的一项
∑ n = 0 ∞ [ x n n ! ] ( x s e t j ) = ∑ n = 0 ∞ ( n + s ) s ‾ j n \sum_{n=0}^{\infty}[\frac{x^n}{n!}](x^se^{tj})=\sum_{n=0}^{\infty}(n+s)^{\underline{s}}j^n n=0[n!xn](xsetj)=n=0(n+s)sjn
暴力展开 ( n + s ) s ‾ (n+s)^{\underline{s}} (n+s)s,现在的问题就变成了给定 s s s,求 ∑ n = 0 ∞ n s j n \sum_{n=0}^{\infty}n^sj^n n=0nsjn
F ( s ) = ∑ n = 0 ∞ n s j n F(s)=\sum_{n=0}^{\infty}n^sj^n F(s)=n=0nsjn, F F F可以通过差分递推求得。
至此整个问题就解决了。
每一步的时间复杂度都是 O ( ( ∑ A i ) 3 ) O((\sum A_i)^3) O((Ai)3)的(假定 ∑ A i \sum A_i Ai ∑ B i \sum B_i Bi同阶)
代码:

#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;
}
AtCoder Practice Contest #B - インタラクティブ練習 (Interactive Sorting) 是一道比较有趣的题目。它是一道交互式的排序题目,需要你与一个神秘程序进行交互,以便将一串无序的数字序列排序。 具体来说,这个神秘程序会给你一个长度为 $N$ 的数字序列,然后你需要通过询问它两个数字的大小关系,来逐步确定这个序列的排序顺序。每次询问之后,神秘程序都会告诉你两个数字的大小关系,比如第一个数字比第二个数字小,或者第二个数字比第一个数字小。你需要根据这个信息,来调整这个数字序列的顺序,然后再向神秘程序询问下一对数字的大小关系,以此类推,直到这个数字序列被完全排序为止。 在这个过程中,你需要注意以下几点: 1. 你最多只能向神秘程序询问 $Q$ 次。如果超过了这个次数,那么你的程序会被判定为错误。 2. 在每次询问之后,你需要及时更新数字序列的顺序。具体来说,如果神秘程序告诉你第 $i$ 个数字比第 $j$ 个数字小,那么你需要将这两个数字交换位置,以确保数字序列的顺序是正确的。如果你没有及时更新数字序列的顺序,那么你的程序也会被判定为错误。 3. 在询问的过程中,你需要注意避免重复询问。具体来说,如果你已经询问过第 $i$ 个数字和第 $j$ 个数字的大小关系了,那么你就不需要再次询问第 $j$ 个数字和第 $i$ 个数字的大小关系,因为它们的大小关系已经被确定了。 4. 在排序完成之后,你需要将排序结果按照从小到大的顺序输出。如果你输出的结果不正确,那么你的程序也会被判定为错误。 总的来说,这道题目需要你熟练掌握交互式程序设计的技巧,以及排序算法的实现方法。如果你能够熟练掌握这些技巧,那么就可以顺利地完成这道非传统题了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值