题解: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;
}
posted @ 2025-07-25 21:39  OIer_wst  阅读(31)  评论(0)    收藏  举报