通用测评号

题目

有 n 个燃料舱,容量均为 a,初始时均为空。
每次等概率随机选择一个没有满的燃料舱,并在其中放入 1 单位燃料。当
所有燃料舱均包含至少 b 单位的燃料时,停止该过程
求结束时期望有多少个燃料舱被填满了,答案对 998244353 取模
1 ≤ n ≤ 250, 1 ≤ b < a ≤ 250

思路

原问题转化为:每个燃料舱容量无限,求在所有燃料舱 ≥ b 的时刻,燃料≥ a 的燃料舱个数的期望
根据期望的线性性,只需要对每个燃料舱考虑,计算在它燃料 = a 的时刻存在其他燃料舱 < b 的概率(在这个局面下,最终所有燃料舱 ≥ b 时,该燃料舱必然 ≥ a),此时概率即为期望。
而所有燃料舱等价,那么对 1 号燃料舱进行计算,乘上 n 即为答案
考虑容斥,钦定有 p 个燃料舱燃料 < b
问题转化为:有一个初始为空的序列,每次等概率随机添加一个 [1, p + 1]的数至序列末尾,计算当序列中出现 a 个 1 时,2 ∼ p + 1 的出现次数均 < b的概率。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1<<17|1,mod=998244353; 
int n,a,B,f[N],g[N],fac[N],inv[N],iac[N],ans; 

ll modow(ll a,int b,ll s=1){for(; b; b>>=1,a=a*a%mod)if(b&1)s=s*a%mod; return s; }
ll C(int n,int m){return (ll)fac[n]*iac[m]%mod*iac[n-m]%mod; }

int main()
{
	scanf("%d%d%d",&n,&a,&B),fac[0]=fac[1]=inv[0]=inv[1]=iac[0]=iac[1]=1; 
	for(int i=2; i<=n*a; ++i) fac[i]=(ll)fac[i-1]*i%mod,iac[i]=iac[i-1]*ll(inv[i]=ll(mod-mod/i)*inv[mod%i]%mod)%mod; 
	for(int i=0; i<B; ++i) f[i]=iac[i]; 
	for(int i=1,sum; i<n; memcpy(f,g,sizeof f),++i)
	{
		for(int j=sum=0,is=modow(inv[i+1],a); j<=i*(B-1); ++j,is=1ll*inv[i+1]*is%mod)
			sum=(sum+1ll*f[j]*fac[j+a-1]%mod*is)%mod; 
		sum=(ll)sum*iac[a-1]%mod,ans=(ans+ll(i&1?1:mod-1)*sum%mod*C(n-1,i))%mod; 
		for(int j=0,Ds=(i+1ll)*iac[B-1]%mod; j<=i*(B-1); ++j)f[j]=1ll*f[j]*Ds%mod; 
		if(B-1)for(int j=i*(B-1); j>=0; --j)f[j+B-1]=f[j],f[j]=0; 
		for(int j=*g=1; j<=(i+1)*(B-1); ++j)g[j]=(g[j-1]*(i+1ll)-f[j-1]+mod)%mod*inv[j]%mod; 
	}
	return printf("%d\n",int((ll)n*ans%mod)),0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值