概率dp AtCoder Beginner Contest 243 F

AtCoder Beginner Contest 243 F

题意

n种彩票,每种彩票i中奖概率为pi ,求抽k次后恰好m种彩票中奖的概率(简化的概率,题目中的概率还要用个逆元)

思路

超几何分布,设抽k次后每种彩票i中奖个数为ci ,则概率为
P=Ckc1p1c1Ckc1c2p2c2Ckc1c2c3p3c3...Cki=1n1cnpncn,化简之后就变成P=k!i=1npicii=1nci!
这样就清晰很多了,设状态f[i][j][k]为当前第i种彩票,已经由j种彩票被抽中,抽了k次的概率;
那么有 f[i][j][k]=f[i1][j(c!=0)][kc]picc!,即当前第i种彩票买了c张,从之前的状态转移过来

代码

const int N=55,inf=0x3f3f3f3f,mod= 998244353;
int n,m,K;
int f[N][N][N],fac[N],p[N],inv_f[N];

int q_pow(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1) res=res*a%mod;
		a=a*a%mod;
		b/=2;
	}
	return res%mod;
}

void init(int n)
{
	fac[0]=inv_f[0]=1;
	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
	inv_f[n]=q_pow(fac[n],mod-2)%mod;
	for(int i=n-1;i>=1;i--) 
	{
		inv_f[i]=inv_f[i+1]*(i+1)%mod;
	}
}

void solve() 
{
	cin>>n>>m>>K;
	init(K+1);
	int sum=0;
	for(int i=1;i<=n;i++) cin>>p[i],sum+=p[i];//分母
	int inv=q_pow(sum,mod-2)%mod;
	f[0][0][0]=1;
	for(int i=1;i<=n;i++) p[i]=p[i]*inv%mod;
	for(int i=0;i<=n;i++) 
	{
	   for(int j=0;j<=i;j++) 
	   {
	      for(int k=0;k<=K;k++) 
	      {
		 for(int c=0;c+k<=K;c++) 
		 {
		    f[i+1][j+(c!=0)][k+c]=(f[i+1][j+(c!=0)][k+c]+f[i][j][k]*q_pow(p[i+1],c)%mod*inv_f[c]%mod)%mod;
		 }
	      }
	   }
	}
	int ans=f[n][m][K]*fac[K]%mod;
	cout<<ans<<endl;
}

长夜路漫漫

posted @   Liang2003  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示