题解 QOJ#9376 游戏
题目大意:
一个游戏,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获胜概率为:
同理,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\)时,
\(0<r<u\)时,
此时再递归计算\(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;
}

浙公网安备 33010602011771号