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