游戏

游戏

题意简述

从 0 星开始,目标达到 n 星。每局游戏:

  • 若当前为 i 星(0 ≤ i < n),获胜概率为 \(p_i = \dfrac{x_i}{y_i}\)(以模 \(998244353\) 意义下给出)。
  • 胜利:星数 +1
  • 失败:星数 -1,但如果当前为 0 星则不减少。

求期望对局次数,答案对 \(998244353\) 取模。


数学推导

设 \(E[i]\) 表示从 \(i\) 颗星出发,到达 \(n\) 颗星的期望对局数。
显然有边界条件:

\(E[n] = 0\)

对于 \(0 \le i < n\),考虑一步转移。

情况 \(i = 0\)

此时失败不减少星数,因此:

\[E[0] = 1 + p_0 \cdot E[1] + (1 - p_0) \cdot E[0] \]

移项:

\[p_0 \cdot (E[0] - E[1]) = 1 \]

所以:

\[E[1] = E[0] - \frac{1}{p_0} \]

情况 \(1 \le i < n\)

\[E[i] = 1 + p_i \cdot E[i+1] + (1 - p_i) \cdot E[i-1] \]

整理得到递推式:

\[E[i+1] = E[i-1] + \frac{1}{p_i} \cdot (E[i] - E[i-1] - 1) \]


化为线性表示

令 \(E[i] = A[i] \cdot E[0] + B[i]\),其中 \(A[i], B[i]\) 是模 \(MOD\) 下的系数。

初始:

  • \(i = 0\):
    \(A[0] = 1\),\(B[0] = 0\)
  • \(i = 1\):
    \(A[1] = 1\),\(B[1] = -\dfrac{1}{p_0}\)

对于 \(i \ge 2\),设 \(p = p_{i-1}\)(即从 \(i-1\) 星获胜的概率),由递推式:

\[E[i] = E[i-2] + \frac{1}{p} \cdot (E[i-1] - E[i-2] - 1) = \left(1 - \frac{1}{p}\right) \cdot E[i-2] + \frac{1}{p} \cdot E[i-1] - \frac{1}{p} \]

因此系数递推:

\[A[i] = \frac{1}{p} \cdot A[i-1] + \left(1 - \frac{1}{p}\right) \cdot A[i-2] \]

\[B[i] = \frac{1}{p} \cdot B[i-1] + \left(1 - \frac{1}{p}\right) \cdot B[i-2] - \frac{1}{p} \]

其中 \(\frac{1}{p}\) 在模意义下即为 \(y_{i-1} \cdot \operatorname{inv}(x_{i-1})\)。

最终,因为 \(E[n] = 0\),有:

\[A[n] \cdot E[0] + B[n] = 0 \Rightarrow E[0] = -\frac{B[n]}{A[n]} \pmod{MOD} \]

所以答案即为 \(E[0]\)。


算法流程

  1. 读入 \(n\),以及 \(n\) 组 \((x_i, y_i)\)(\(i = 0 \dots n-1\))。
  2. 预处理 \(1/p_0\) 并初始化 \(A[0], B[0], A[1], B[1]\)。
  3. 从 \(i = 2\) 到 \(n\) 循环:
    • 计算 \(p = \dfrac{x_{i-1}}{y_{i-1}}\),得到 \(\operatorname{inv}p = y_{i-1} \cdot \operatorname{inv}(x_{i-1})\)。
    • 令 \(c_1 = \operatorname{inv}p\),\(c_2 = 1 - \operatorname{inv}p\)。
    • \(A[i] = c_1 \cdot A[i-1] + c_2 \cdot A[i-2]\)
    • \(B[i] = c_1 \cdot B[i-1] + c_2 \cdot B[i-2] - \operatorname{inv}p\)
  4. 计算 \(\text{ans} = -B[n] \cdot \operatorname{inv}(A[n]) \pmod{MOD}\)。
  5. 输出 \(\text{ans}\)。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;

struct wait {
    ll k;
    ll num;
};

ll modpow(ll a, ll b) {
    ll r = 1;
    while(b) {
        if(b&1) r = r * a % MOD;
        a = a*a%MOD;
        b >>= 1;
    }
    return r;
}

void solve() {
    int n; cin >> n;
    vector<ll> x(n + 1, 0), y(n + 1, 0);
    for(int i = 0; i < n; i ++) cin >> x[i] >> y[i];
    vector<wait> dp(n + 1);
    dp[0].k = 1, dp[0].num = 0;
    ll p0_ = y[0] * modpow(x[0], MOD-2) % MOD;;
    dp[1].k = 1, dp[1].num = (-p0_ + MOD)%MOD;

    for(int i = 2; i <= n; i ++) {
        ll tx = x[i-1], ty = y[i-1];
        ll pi1 = tx * modpow(ty, MOD-2) % MOD; pi1 = (pi1 - 1 + MOD) % MOD;
        ll pi_q = ty * modpow(tx, MOD-2) % MOD;
        dp[i].k = (dp[i-1].k + pi1*dp[i-2].k % MOD + MOD) % MOD * pi_q % MOD;
        dp[i].num = (dp[i-1].num + pi1*dp[i-2].num % MOD - 1 + MOD)  % MOD * pi_q % MOD;
    }
    ll qw = modpow(dp[n].k, MOD-2);
    ll ans = -dp[n].num * qw % MOD;
    if(ans < 0) ans += MOD;
    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    int _=1; //cin >> _;
    while(_--) solve();
    return 0;
}
posted @ 2026-09-08 19:54  thenrify  阅读(7)  评论(0)    收藏  举报