CF601 C 题解

C:

题意:m个人参加n场比赛,每个人最终排名为每次比赛名次相加排序,已知主角每场比赛的名次,求其最终排名的期望值。(n<=100, m<=1000)

Solution:

好家伙完全没有思路,看题解发现原来期望dp还能这么玩儿。

\(f[i][j]\) 表示前 i 场比赛名次和为 j 的人数期望有多少个。

我们发现这个状态是可以转移的,而且转移方程很好写:

\(f[i][j] = \frac{\sum\limits_{k=1}^{m}f[i-1][j-k]\ \ \ (k\neq a[i])}{m-1}\)

这是什么呢,就是说如果一些人想要在 i 场比赛后名次和为 j ,他们可以是前 i-1 场和为 j-k,第 i 场名次为 k。\(f[i][j]\) 这个状态的值,就是前一场的那些期望人数乘上可以转移到此状态的概率,求和。

由于 k 不能和 a[i] 相等,因此对于所有人,第 i 场名次为 k 的概率都是 \(\frac 1{m-1}\)

最终答案就是严格小于主角名次和的人数的期望值 \(f[n][0]\sim f[n][sum-1]\) 再加一。

整个dp过程用前缀和优化,复杂度O(n^2m)。

typedef long double ld;

int T;
int n,m;
int ans,a[N];
ld f[2][111111];
int da,he;

int main() {
	n = read(); m = read(); da = n*m;
    if(m==1) {cout<<"1.0000000000000000"<<endl; return 0;}
    for(int i=1;i<=n;i++) a[i] = read(), he += a[i];
    for(int i=0;i<=da;i++) f[0][i] = m-1;
    for(int i=1;i<=n;i++) {
        int cl = i&1;
        f[cl][0] = 0.0;
        for(int j=1;j<=da;j++) {
            f[cl][j] = f[cl][j-1] + (f[cl^1][j-1] - ((j-m-1>=0)?f[cl^1][j-m-1]:0) - ((j-a[i]>=0)?f[cl^1][j-a[i]]:0) + ((j-a[i]-1>=0)?f[cl^1][j-a[i]-1]:0)) / (ld)(m-1.0);
        }
    }
    printf("%.12Lf",f[n&1][he-1]+1.0);
    return 0;
}

posted @ 2024-02-22 00:18  maple276  阅读(10)  评论(0编辑  收藏  举报