[HOJ] 最高分
题目大意
\(n\) 人参加 \(m\) 轮比赛,第 \(i\) 个人在第 \(j\) 场比赛拿到 \(k\) 分的概率是 \(a_{i,j,k}\),每一场比赛有且只有一人能够拿分,求 \(m\) 场比赛结束后选手中最高分的期望是多少。
保证 \(\forall i\in[1,m],\sum\limits_{j=1}^n\sum\limits_{k=1}^3 a_{j,i,k}=1\)
\(1\le n\le 20,1\le m\le 10,1\le k\le 3\)
解题思路
看到如此小的 \(m\),可以想到状压dp。
因为最终答案要求的是最大值的期望,所以我们可以考虑用一维存储最大值,\(f\) 的值表示到达该状态的概率,求期望时将两项相乘求和即可。
但是如果将每个人 "分配" 给每场比赛,会发现并不好转移,所以我们考虑反过来,枚举每个人,再定赢了哪些比赛。
所以我们可以想到令 \(f_{i,j,k,w}\) 表示枚举到第 \(i\) 个人,第 \(i\) 个人得了 \(j\) 分,前 \(i\) 个人中最高分为 \(k\),\(w\) 这些比赛的胜者已经确定的概率。
所以得到了转移方程:
\[f_{i,j,k,w}=\begin{cases}\sum\limits_{l\in w}\sum\limits_{t=1}^3f_{i,j-t,k,w-l}\ a_{i,l,t}&k> j\\
\sum\limits_{l\in w}\sum\limits_{t=1}^3(f_{i,j-t,j-t,w-l}+f_{i,j-t,k,w-l})\ a_{i,l,t}&k=j\\
\end{cases}
\]
第二行表示第 \(i\) 个人是新的最高分的概率。
特别地,有:
\[f_{i,0,k,w}=\sum\limits_{j=0}^k f_{i-1,j,k,w}
\]
时间复杂度为 \(O(nm^32^m)\)
细节
注意多层循环的顺序,否则会导致重复统计。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int ll
const int N = 22, M = 11, p = 1e9 + 7;
int f[N][M * 3][M * 3][1 << M], a[M][N][3], n, m;
ll qpow(ll a, ll b)
{
if(b == 1) return a;
return (b & 1) ? a * qpow(a * a % p, b >> 1 ) % p : qpow(a * a % p, b >> 1);
}
int inv = qpow(1e6, p - 2);
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> n >> m;
for(int w = 1; w <= 3; w ++)
for(int i = 1; i <= m; i ++)
for(int j = 1; j <= n; j ++)
{
cin >> a[i][j][w];
a[i][j][w] = a[i][j][w] * inv % p;
}
f[0][0][0][0] = 1;
int _2m = 1 << m, m3 = m * 3;
for(int i = 1; i <= n; i ++)
{
int ss = 0;
for(int j = 0; j <= m3; j ++)
for(int k = j; k <= m3; k ++)
for(int w = 0; w < _2m; w ++)
f[i][0][k][w] = (f[i][0][k][w] + f[i - 1][j][k][w]) % p;
for(int l = 0; l < m; l ++)
for(int w = 0; w < _2m; w ++)
{
if(!(w & (1 << l))) continue;
int nw = w ^ (1 << l);
for(int j = m3; j >= 0; j --)
{
int &ff = f[i][j][j][w];
for(int k1 = max(j - 3, 0ll); k1 < j; k1 ++)
{
if(j - 1 >= 0 && j - 1 <= k1) ff = (ff + f[i][j - 1][k1][nw] * a[l + 1][i][1]) % p;
if(j - 2 >= 0 && j - 2 <= k1) ff = (ff + f[i][j - 2][k1][nw] * a[l + 1][i][2]) % p;
if(j - 3 >= 0 && j - 3 <= k1) ff = (ff + f[i][j - 3][k1][nw] * a[l + 1][i][3]) % p;
}
for(int k = j; k <= m3; k ++)
{
int &now = f[i][j][k][w];
if(j - 1 >= 0) now = (now + f[i][j - 1][k][nw] * a[l + 1][i][1]) % p;
if(j - 2 >= 0) now = (now + f[i][j - 2][k][nw] * a[l + 1][i][2]) % p;
if(j - 3 >= 0) now = (now + f[i][j - 3][k][nw] * a[l + 1][i][3]) % p;
}
}
}
}
int ans = 0, _end = _2m - 1, ss = 0;
for(int i = 0; i <= m3; i ++)
for(int j = i; j <= m3; j ++)
{
ans = (ans + j * f[n][i][j][_end]) % p;
ss = (ss + f[n][i][j][_end]) % p;
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号