2018 ACM-ICPC World Finals Gym-102482D Gem Island

题目传送门

分析:
期望=总价值/方案数
于是就想办法算这两个。。。
每个村民一个宝石,每天一个村民的一个宝石一分为二
相当于最初都没有宝石,每天一个村民可以获得一个宝石
效果是等价的
问题变成了将\(d\)个宝石随机分给\(n\)个村民,求拥有最多宝石的\(r\)个人手上宝石的价值和
设将\(d\)个宝石分给\(n\)个村民的方案数为\(F_{n,d}\)
列出式子:

\[F_{i,j}=\sum_{k=0}^{min(i,j)}\binom{i}{k}F_{k,j-k} \]

意义为枚举到目前还有\(i-k\)个村民手上还没有宝石,剩下的的\(k\)个村民一人得到一个宝石
设将\(d\)个宝石分给\(n\)个村民的所有方案中,前\(r\)个人手上宝石的和的总和为\(G_{n,d}\)
列出式子:

\[G_{i,j}=\sum_{k=0}^{min(i,j)}\binom{i}{k}(G_{k,j-k}+min(k,r)F_{k,j-k}) \]

意义与上面类似
复杂度\(O(n^3)\)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>

#define maxn 1005
#define MOD 998244353

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,d,r;
long double C[maxn][maxn],F[maxn][maxn],G[maxn][maxn];

int main()
{
	n=getint(),d=getint(),r=getint();
	for(int i=0;i<=max(n,d);i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
	}
	F[0][0]=1;
	for(int i=1;i<=n;i++)for(int j=0;j<=d;j++)for(int k=0;k<=min(i,j);k++)
	{
		F[i][j]+=C[i][k]*F[k][j-k];
		G[i][j]+=C[i][k]*(G[k][j-k]+min(k,r)*F[k][j-k]);
	}
	printf("%.8lf\n",double(G[n][d]/F[n][d])+r);
}

猜你喜欢

转载自www.cnblogs.com/Darknesses/p/13195356.html