题解 QOJ#9376 游戏

G. 游戏

题目大意:

一个游戏,Alice初始时为\(x\),Bob初始为\(y\)
每回合Alice赢的概率是\(p_0\),Bob赢的概率是\(p_1\),平局的概率是\(1-p_0-p_1\).

对于每回合,如果平局,则直接下一回合;
如果Alice获胜:\(x\ge y\)则游戏结束,Alice最终获胜;否则\(y=y-x\)
如果Bob获胜:\(x\le y\)则游戏结束,Bob最终获胜;否则\(x=x-y\).

1.概率归一化

平局什么都不发生,因此可以忽略。

设每回合Alice获胜的概率为\(p_0\),Bob获胜的概率为\(p_1\),平局概率为\(p_d=1-p_0-p_1\).

我们把“平局若干回合+第一次决出胜负”定义为新的“回合”,则Alice获胜概率为:

\[P_A=\sum_{n=0}^{\infty}p_d^np_0=\frac{p_0}{1-p_d}=\frac{p_0}{p_0+p_1} \]

同理,Bob获胜概率为\(P_B=\frac{p_1}{p_0+p_1}\)

因此,\(P_A+P_B=1\),这就实现了概率的归一化。

2.利用对称性简化问题

我们只需要分析较小者最终获胜的概率\(P(u,v)\)其中\(u\le v\).

\(x\le y\)时,答案即为\(P(x,y)\)

\(x>y\)时,答案为\(P(x,y)=1-P(y,x)\).

3.递归计算\(P(u,v)\)\(u\le v\)

设当前回合\(u\)获胜概率为\(p_u\)\(v\)获胜概率为\(p_v\).

由题意得:\(u=v\)时,\(P(u,v)=P(u,u)=p_u\)

否则\(u<v\)时,\(P(u,v)=p_uP(u,v-u)\).

\(v=ku+r\),其中\(k\ge 1\)\(0\le r<u\).

\(r=0\)时,

\[P(u,v)=p_uP(u,v-u)=\dots=p_u^{k-1}P(u,u)=p^k \]

\(0<r<u\)时,

\[P(u,v)=p_uP(u,v-u)=\dots=p_u^{k}P(u,r) \]

此时再递归计算\(P(u,r)\)即可。

整理一下可得:

\(P(0,x)=0\),则\(u\le v\)\(P(u,v)=p_u^{\left\lfloor \frac{v}{u}\right\rfloor }(1-P(v\bmod u,v))\)

这正是辗转相除的过程,最后一定能结束,递归深度为\(O(logn)\).

总时间复杂度\(O(Tlogn)\).

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define pii pair<int, int>
#define pdd pair<double, double>
#define PI acos(-1.0)
#define endl '\n'

using namespace std;

const int N = 1e5 + 10, M = 1e6 + 10, INF = 1000000000000000000, MOD = 998244353;
const double eps = 1e-8;

inline int mod(int x) {//取模
    return (x % MOD + MOD) % MOD;
}

inline int qpow(int x, int p) {//快速幂
    x = mod(x);
    int res = 1;
    while (p) {
        if (p & 1) res = res * x % MOD;
        x = x * x % MOD;
        p >>= 1;
    }
    return mod(res);
}

int P(int u, int v, int pu, int pv) {//递归
    if (!u) return 0;
    int k = v / u, r = v % u;
    return mod(qpow(pu, k) * mod(1 - P(r, u, pv, pu)));
}

void solve(){
    int x, y; cin >> x >> y;
    int a0, a1, b; cin >> a0 >> a1 >> b;
    b = qpow(a0 + a1, MOD - 2);//归一化
    a0 = mod(a0 * b);
    a1 = mod(a1 * b);
    if (x <= y) cout << P(x, y, a0, a1) << endl;
    else cout << mod(1 - P(y, x, a1, a0)) << endl;
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int T; cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}
posted @ 2026-09-05 00:27  Luliaaa  阅读(12)  评论(0)    收藏  举报