不公平对局

不公平的对局

小红执黑先手,每回合依次进行:

  1. 小红以概率 p1 = a1/b1 吃掉小紫一枚棋子;
  2. 小紫以概率 p2 = a2/b2 吃掉小红一枚棋子。

任何一方累计吃子数达到 x 即判负。求小红最终获胜的概率,对 MOD = 1e9+7 取模输出。

输入:xa1 b1a2 b2(保证 a1,a2 不同时为 0)
输出:模意义下的答案分数。

状态定义

dp[i][j] 表示当前小红已吃 i 枚、小紫已吃 j 枚,且均未达到 x 时,小红最终获胜的概率。

边界条件

  • dp[x][j] = 0(小红先达到 x,输)
  • dp[i][x] = 1(小紫先达到 x,小红赢)

转移方程

设:

  • 小红吃子概率 p1,不吃 q1 = 1 - p1
  • 小紫吃子概率 p2,不吃 q2 = 1 - p2

一回合四种情况:

小红 小紫 概率 下一状态
p1*p2 dp[i+1][j+1]
不吃 p1*q2 dp[i+1][j]
不吃 q1*p2 dp[i][j+1]
不吃 不吃 q1*q2 dp[i][j](自环)

移项得:

dp[i][j] = ( p1*p2*dp[i+1][j+1] + p1*q2*dp[i+1][j] + q1*p2*dp[i][j+1] ) / (1 - q1*q2)

分母 D = 1 - q1*q2 = p1 + p2 - p1*p2,保证非零。

计算顺序

由于依赖 i+1 和同一行 j+1,采用倒序枚举:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

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 x; cin >> x;
    ll a, b, c, d; cin >> a >> b >> c >> d;
    ll p1 = modpow(b, MOD - 2) * a % MOD, p2 = modpow(d, MOD - 2) * c % MOD;
    ll q1 = (1 - p1 + MOD) % MOD, q2 = (1 - p2 + MOD) % MOD;
    ll y = (1 - q1 * q2 % MOD + MOD) % MOD;
    y = modpow(y, MOD - 2);
    vector<vector<ll>> dp(x + 1, vector<ll>(x + 1, 0));
    for(int i = 0; i < x; i ++) dp[i][x] = 1;
    for(int i = x - 1; i >= 0; i --) for(int j = x - 1; j >= 0; j --) {
        ll w1 = dp[i][j + 1] * q1 % MOD * p2 % MOD;
        ll w2 = dp[i + 1][j] * p1 % MOD * q2 % MOD;
        ll w3 = dp[i + 1][j + 1] * p1 % MOD * p2 % MOD;
        dp[i][j] = (w1 + w2 + w3) % MOD * y % MOD;;
    }
    cout << dp[0][0] << "\n";
}

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