P5415 [YNOI2019] 游戏 题解
思路
首先,这道题是一道显然的概率题。直接上 DP。
我们称当前的赢家为擂主。设 \(dp_{i, j}\) 代表第 \(k\) 个人在 \(i\) 号位置,擂主已经连赢 \(j\) 场时,第 \(k\) 个人获胜的概率。那我们以第 \(k\) 个人的位置分类讨论。
1. 当 \(k\) 为擂主时:
此时 \(k\) 所在的位置为 \(1\)。那 \(k\) 就有 \(\dfrac{1}{4}\) 的概率再赢 \(1\) 局,有 \(\dfrac{3}{4}\) 输掉比赛。若输掉比赛,\(k\) 应排到第 \(n - 2\) 位置。
故可以得到状态转移方程:
\[dp_{1,j}=dp_{1,j+1}\times \dfrac{1}{4}+dp_{n-2,1}\times \dfrac{3}{4}
\]
2. 当 \(k\) 在比赛中,但不是擂主时:
此时需要分别讨论 \(k\) 在 \(2\),\(3\),\(4\) 位置的情况,还需要进一步讨论是谁赢了这几种情况。这十分复杂,留给读者自己推导。最后可得下述几个状态转移方程:
\[dp_{2,j}=dp_{1,1}\times \dfrac{1}{4}+dp_{n-2,j+1}\times \dfrac{1}{4}+dp_{n-1,1}\times \dfrac{1}{2}\\
dp_{3,j}=dp_{1,1}\times \dfrac{1}{4}+dp_{n-1,j+1}\times \dfrac{1}{4}+dp_{n,1}\times \dfrac{1}{4}+dp_{n-1,1}\times \dfrac{1}{4}\\
dp_{4,j}=dp_{1,1}\times \dfrac{1}{4}+dp_{n,1}\times \dfrac{1}{2}+dp_{n-2,j+1}\times \dfrac{1}{4}
\]
3. 当 \(k\) 在队伍中时:
此时只与当前擂主的输赢即可。易得下述状态转移方程:
\[dp_{i,j}=dp_{i-3,j+1}\times \dfrac{1}{4}+dp_{i-3,1}\times \dfrac{3}{4}
\]
其中 \(5 \le i \le n\)。
最后答案就是 \(dp_{k,0}\)。
但你会发现,DP 无法转移,因为有互相的依赖性。可因为 \(n \le 10\),\(m \le 10\),所以可以直接跑高斯消元。
最后时间复杂度为 \(O(n^3m^3)\),可以通过本题。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 155;
const double eps = 1e-12;
int t, n, m, k;
double a[N][N];
int calc(int x, int y)
{
return (x - 1) * (m + 1) + y;
}
void gauss(int n)
{
for (int i = 0; i < n; i++)
{
int id = i;
for (int j = i + 1; j < n; j++)
if (fabs(a[j][i]) > fabs(a[id][i])) id = j;
if (fabs(a[id][i]) < eps) continue;
swap(a[i], a[id]);
double div = a[i][i];
for (int j = 0; j <= n; j++)
a[i][j] /= div;
for (int j = i + 1; j < n; j++)
{
double mul = a[j][i];
for (int k = i; k <= n; k++)
a[j][k] -= a[i][k] * mul;
}
}
for (int i = n - 1; i >= 0; i--)
{
for (int j = i - 1; j >= 0; j--)
{
a[j][n] -= a[j][i] * a[i][n];
a[j][i] = 0;
}
}
return;
}
void solve()
{
memset(a, 0, sizeof(a));
scanf("%d%d%d", &n, &m, &k);
int cur = 0, maxp = n * (m + 1);
a[cur][calc(1, m)] += 1.0, a[cur][maxp] += 1.0;
cur++;
for (int i = 2; i <= n; i++)
{
a[cur][calc(i, m)] += 1.0;
cur++;
}
for (int i = 0; i < m; i++)
{
a[cur][calc(1, i)] += 1.0;
a[cur][calc(1, i + 1)] -= 0.25;
a[cur][calc(n - 2, 1)] -= 0.75;
cur++;
}
for (int i = 0; i < m; i++)
{
a[cur][calc(2, i)] += 1.0;
a[cur][calc(1, 1)] -= 0.25;
a[cur][calc(n - 2, i + 1)] -= 0.25;
a[cur][calc(n - 1, 1)] -= 0.5;
cur++;
}
for (int i = 0; i < m; i++)
{
a[cur][calc(3, i)] += 1.0;
a[cur][calc(1, 1)] -= 0.25;
a[cur][calc(n - 1, 1)] -= 0.25;
a[cur][calc(n - 1, i + 1)] -= 0.25;
a[cur][calc(n, 1)] -= 0.25;
cur++;
}
for (int i = 0; i < m; i++)
{
a[cur][calc(4, i)] += 1.0;
a[cur][calc(1, 1)] -= 0.25;
a[cur][calc(n, i + 1)] -= 0.25;
a[cur][calc(n, 1)] -= 0.5;
cur++;
}
for (int i = 5; i <= n; i++)
{
for (int j = 0; j < m; j++)
{
a[cur][calc(i, j)] += 1.0;
a[cur][calc(i - 3, j + 1)] -= 0.25;
a[cur][calc(i - 3, 1)] -= 0.75;
cur++;
}
}
gauss(maxp);
double ans = a[calc(k, 0)][maxp];
printf("%.6lf\n", ans);
return;
}
int main()
{
scanf("%d", &t);
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号