这是一道很好的概率dp的题,适合刚学概率dp的同学。(下面用T代表Takahashi,用A代表Aoki)
这道题需要的变量:T在哪个点、A在哪个点以及下一步该谁走。
所以这道题dp的状态即为:
-
f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0] 表示T在 i i i 点, A在 j j j 点, 下一步该T走时,T赢的概率。
-
f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1] 表示T在 i i i 点, A在 j j j 点, 下一步该A走时,T赢的概率。
考虑完状态,来考虑初值。
概率dp一般都是某个事件必然发生或某个事件不可能发生,那么这道题的初值就是考虑T在什么情况下必赢,在什么情况下必输。
- 必赢:T已经在n这个点了,不管下一步谁走都赢,即 对于 1 ⩽ i < n 1 \leqslant i < n 1⩽i<n 有 f [ n ] [ i ] [ 0 ] = f [ n ] [ i ] [ 1 ] = 1 f[n][i][0] = f[n][i][1] = 1 f[n][i][0]=f[n][i][1]=1
- 必输:A已经在n这个点了,不管下一步谁走都输,即 对于 1 ⩽ i < n 1 \leqslant i < n 1⩽i<n 有 f [ i ] [ n ] [ 0 ] = f [ i ] [ n ] [ 1 ] = 0 f[i][n][0] = f[i][n][1] = 0 f[i][n][0]=f[i][n][1]=0
那么状态也就自然而然出来了。
- f [ i ] [ j ] [ 0 ] = 1 p ∑ i = 1 p f m i n ( i + k , n ) , j , 1 f[i][j][0] = \frac{1}{p}\sum_{i = 1}^pf_{min(i+k, n), j, 1} f[i][j][0]=p1∑i=1pfmin(i+k,n),j,1
- f [ i ] [ j ] [ 1 ] = 1 q ∑ i = 1 q f n , m i n ( j + k , m ) , 0 f[i][j][1] = \frac{1}{q}\sum_{i = 1}^qf_{n, min(j+k, m), 0} f[i][j][1]=q1∑i=1qfn,min(j+k,m),0
那么答案就是 f [ a ] [ b ] [ 0 ] f[a][b][0] f[a][b][0], 即T在 a a a 点, A在 b b b 点, 下一步该T走。
#include <iostream>
#define int long long
using namespace std;
const int NR = 110;
const int MOD = 998244353;
int f[NR][NR][2];
int ksm(int a, int b)
{
int ans = 1;
while (b)
{
if (b & 1) ans = ans * a % MOD;
b >>= 1;
a = a * a % MOD;
}
return ans;
}
int inv(int x)
{
return ksm(x, MOD - 2); // 用费马小定理求逆元
}
signed main()
{
int n, A, B, P, Q;
cin >> n >> A >> B >> P >> Q;
for (int i = 0; i < n; i++)
f[n][i][0] = f[n][i][1] = 1, f[i][n][0] = f[i][n][1] = 0;
long long p = inv(P), q = inv(Q);
for (int i = n - 1; i >= A; i--) // 因为初始位置在A, 所以只枚举到A即可
for (int j = n - 1; j >= B; j--) // 与i同理
{
for (int k = 1; k <= P; k++)
f[i][j][0] = (f[i][j][0] + f[min(i + k, n)][j][1]) % MOD;
f[i][j][0] = f[i][j][0] * p % MOD;
for (int k = 1; k <= Q; k++)
f[i][j][1] = (f[i][j][1] + f[i][min(j + k, n)][0]) % MOD;
f[i][j][1] = f[i][j][1] * q % MOD;
}
cout << f[A][B][0] << '\n';
return 0;
}