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);
}