把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷6944】[ICPC2018 WF] Gem Island(DP)

点此看题面

  • \(n\)个人,初始每个人有一颗宝石。
  • 每天会等概率随机一颗宝石分裂成两颗,求\(d\)天后宝石数前\(r\)多的人的宝石数之和的期望。
  • \(n,d\le500\)

每种局面概率相等

假设第\(i\)个人最终拥有\(1+a_i\)颗宝石,现在我们想要计算这种局面出现的概率。

我们先假定一种分裂顺序计算概率,方案数独立考虑每一个人的贡献应该是\(a_i!\),总方案数则显然是\(n^{\overline d}\),因此概率为\(\frac{\prod_{i=1}^na_i!}{n^{\overline d}}\)

于是发现分裂顺序其实不影响概率,而这种最终局面的分裂顺序数就是一个可重全排列\(\frac{d!}{\prod_{i=1}^na_i!}\)

二者相乘,则一种局面出现的概率就是\(\frac{d!}{n^{\overline{d}}}\),与\(a_i\)什么的完全没有任何关系。

因此,每种最终局面的概率是相等的。

动态规划

这道题要求前\(r\)大的数之和,一种套路做法是从全\(0\)开始,每次给最大值中的若干个数加上\(1\)

具体地,我们设\(f_{i,j}\)表示把\(j\)个数分给\(i\)个人的所有方案下前\(r\)大值的总和,\(g_{i,j}\)表示把\(j\)个数分给\(i\)个人的方案数。

枚举选择其中多少个人加上\(1\),得到:

\[f_{i,j}=\sum_{k=1}^{\min\{i,j\}}C_i^k\times(f_{k,j-k}+g_{k,j-k}\times\min\{k,r\})\\ g_{i,j}=\sum_{k=1}^{\min\{i,j\}}C_i^k\times g_{k,j-k} \]

最终答案是\(r+\frac{f_{n,d}}{g_{n,d}}\),其中的\(r\)表示初始局面下这\(r\)个人各自原有的\(1\)颗宝石,\(DP\)过程只是考虑了\(d\)天里宝石的分配情况,而并没有计算这一贡献。

代码:\(O(n^3)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500
#define DB double
using namespace std;
int n,d,r;DB f[N+5][N+5],g[N+5][N+5],C[N+5][N+5];
int main()
{
	scanf("%d%d%d",&n,&d,&r);
	RI i,j;for(C[0][0]=i=1;i<=n;++i) for(C[i][0]=j=1;j<=n;++j) C[i][j]=C[i-1][j-1]+C[i-1][j];//预处理组合数
	RI k;for(g[0][0]=i=1;i<=n;++i) for(g[i][0]=j=1;j<=d;++j)
		for(k=1;k<=min(i,j);++k) f[i][j]+=C[i][k]*(f[k][j-k]+g[k][j-k]*min(k,r)),g[i][j]+=C[i][k]*g[k][j-k];//枚举选择多少个数加1
	return printf("%.12lf\n",r+f[n][d]/g[n][d]),0;//计算最终答案,注意加上r
}
posted @ 2021-06-02 17:50  TheLostWeak  阅读(84)  评论(0编辑  收藏  举报