题解:P5249 [LnOI2019] 加特林轮盘赌
P5249 [LnOI2019] 加特林轮盘赌
题意
有 \(n\) 个人围成一个环。从 \(1\) 开始游戏,每人每次有 \(P\) 的概率出局,当只剩余一个人时剩余的人获胜。
求出第 \(m\) 个人获胜的概率。
\(m\le n\le10^4\)。
解法
令 \(f_{i,j}\) 表示剩余 \(i\) 个人时,相对位置为 \(j\) 的人获胜的概率。
考虑第 \(1\) 个人:
- 出局。后面每个人往前移动一位,同时总人数减一。获得概率为 \(p\times f_{i-1,j-1}\)。
- 不出局。后面每个人往前移动一位。获得概率为 \((1-p)\times f_{i,j-1}\)。
特别的,\(f_{i,1}\gets (1-p)\times f_{i,i}\),因为 \(1\) 移动后位置为 \(i\)。
那么我们可以得到如下的转移方程:
\[f_{i,j}\gets
\begin{cases}
f_{i-1,j-1}p+f_{i,j-1}(1-p)&i\ne 1\\
f_{i,i}(1-p)&i=1
\end{cases}
\]
可以发现这个方程是存在环的,\(f_{i,j}(i\ne 1)\) 需要 \(f_{i,j-1}\),而 \(f_{i,1}\) 又需要 \(f_{i,i}\)。
考虑手动消元。
令 \(f_{i,i}=x\),\(q=1-p\),则可以推得:
-
\(f_{i,1}=xq\)。
-
\(f_{i,2}=f_{i-1,1}p+xq^2\)。
-
\[\begin{aligned} f_{i,3}&=f_{i-1,2}p+(f_{i-1,1}p+xq^2)q\\ &=f_{i-1,2}p+f_{i-1,1}pq+xq^3\\ &=q^3x+f_{i-1,2}p+f_{i-1,1}pq \end{aligned} \]
-
\[\begin{aligned} f_{i,4}&=f_{i-1,3}p+f_{i,3}(1-p)\\ &=f_{i-1,3}p+q(q^3x+f_{i-1,2}p+f_{i-1,1}pq)\\ &=f_{i-1,3}p+q^4x+f_{i-1,2}pq+f_{i-1,1}pq^2\\ &=q^4x+f_{i-1,3}p+q^4x+f_{i-1,2}pq+f_{i-1,1}pq^2 \end{aligned} \]
-
由此我们就可以发现规律
\[f_{i,j}=q^{j}x+\sum\limits_{k=1}^{j-1}f_{i-1,k}pq^{j-k-1} \] -
\[f_{i,i}=q^ix+\sum\limits_{k=1}^{i-1}f_{i-1,k}pq^{i-k-1} \]
同时 \(f_{i,i}=x\),所以
\[\begin{aligned}
q^ix+\sum\limits_{k=1}^{i-1}f_{i-1,k}pq^{i-k-1}&=x\\
(1-q^i)x&=\sum\limits_{k=1}^{i-1}f_{i-1,k}pq^{i-k-1}\\
x&=\dfrac{\sum\limits_{k=1}^{i-1}f_{i-1,k}pq^{i-k-1}}{1-q^i}
\end{aligned}
\]
由此可以得出每一项。
时间复杂度
\(O(n^2)\)。
代码
/**
* Problem: P5249 [LnOI2019] 加特林轮盘赌
* Author: OIer_wst
* Date: 2025-07-25
*/
#include <bits/stdc++.h>
using lint = long long;
using pii = std::pair<int, int>;
const int N = 1e4 + 10;
int n, k;
double p, q, f[2][N], Q[N];
int main() {
std::cin >> p >> n >> k, q = 1 - p;
if (p == 0) {
std::cout << (k == 1 ? 1 : 0) << std::endl;
return 0;
}
Q[0] = 1;
for (int i = 1; i <= n; ++i) Q[i] = Q[i - 1] * q;
f[1][1] = 1;
for (int i = 2; i <= n; ++i) {
double x = 0;
for (int k = 1; k < i; ++k)
x += f[i - 1 & 1][k] * p * Q[i - k - 1];
x /= 1 - Q[i];
f[i & 1][1] = x * (1 - p);
for (int j = 2; j <= i; ++j)
f[i & 1][j] = f[i - 1 & 1][j - 1] * p + f[i & 1][j - 1] * q;
}
std::cout << std::fixed << std::setprecision(10) << f[n & 1][k] << std::endl;
return 0;
}

浙公网安备 33010602011771号