P6944-[ICPC2018 WF]Gem Island【数学期望,dp】


正题

题目链接:https://www.luogu.com.cn/problem/P6944


题目大意

\(n\)颗不同颜色的宝石,每次随机选择一颗复制,重复\(d\)次,求最后宝石数前\(r\)的颜色的宝石数之和的期望值。

\(1\leq r\leq n,d\leq 300\)


解题思路

考虑一种最终状态\(S\)的概率,设第\(i\)种宝石个数为\(a_i+1\),那么我们考虑在若干次分裂中分裂到这几个的概率,这里先考虑分子作为权重(因为分母一样)。
首先分裂天数分配到每一种宝石的方案就是可重排列的公式:\(\frac{d!}{\prod_{i=1}^na_i!}\)
然后对于第\(i\)次分裂一种宝石时,有\(i\)的概率,所以这一部分的方案就是\(\prod_{i=1}^na_i!\)
那么总共的权重
\[\frac{d!}{\prod_{i=1}^na_i!}\times \prod_{i=1}^na_i!=d!\]

所以所有方案的概率都是相等的。

之后考虑怎么求所有方案的,我们可以考虑\(dp\)

\(dp\)求前\(r\)大的和话我们有个很常见的技巧,就是我们可以每次让一个前缀\(+1\),然后不断缩短前缀,这样我们还可以在缩短前缀的过程中顺便统计重排的方案。

\(f_{i,j}\)表示目前分裂了\(i\)次,前缀长度为\(j\)时的方案数,\(g\)则表示所有方案的答案,然后转移即可。

时间复杂度:\(O(n^3)\)


code

#include
#include
#include
using namespace std;
const int N=510;
int n,d,r;
double C[N][N],f[N][N],g[N][N];
int main()
{
    scanf("%d%d%d",&n,&d,&r);
    C[0][0]=f[0][n]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=i;j++)
            C[i][j]=C[i-1][j]+(j?C[i-1][j-1]:0);
    for(int i=0;id)break;
                f[i+k][k]+=f[i][j]*C[j][k];
                g[i+k][k]+=(g[i][j]+min(r,k)*f[i][j])*C[j][k];
            }
    double F=0,G=0;
    for(int i=1;i<=n;i++)
        F+=f[d][i],G+=g[d][i];
    printf("%.12lf\n",G/F+r);
    return 0;
}