Probability of winning in a Die-throw game
Last Updated :
18 Jul, 2023
Given that 2 players are playing a die-throw game. The game is one player throws a die and he got a point, he can move forward accordingly to the point. All occurrences to get the point have equal probability. Let player1 start a point x and player2 start a point y. Player 1 can receive a point up to A, and Player 2 can receive a point up to B. When a player in the position p and point got in the die q, he can move forward a minimum of (p+q) and W. The first player to reach W wins the game. Find the probability modulo that player 1 wins if he goes first modulo 998244353.
To find a probability modulo of 998244353. We can represent the probability as an irreducible fraction y/x, then x is indivisible by 998244353. So, there is a unique integer z between 0 and 998244352 such that xz ≡ y(mod998244353). Find this z.
Examples:
Input W = 6, x = 3, y =2, A = 5, B = 4
Output 586363698
Input W = 5, x = 3, y = 2, A = 1, B = 1
Output 0
Approach: This can be solved with the following idea:
This problem can be solved using dynamic programming. Let dpi, j, f be the probability that player1 wins when player1 and player2 are at points i and j respectively, where f=0 if the turn is player1’s and f=1 if player2’s. The sought value is dpA, B, 0. We first consider the value dpi, j, 0. For k=1, 2, …A, player1 moves forward to point min(i+k, W) with equal probability, so dpi, j, 0 = 1/A∑Ak=1dpmin(i+k, W), j, 1. Similarly, we consider dpi, j, 1 for k = 1, 2, …B, player2 moves forward to point min(j+k, W) with equal probability, so dpi, j, 0 = 1/A∑Bk=1dpi, min(j+k, W), 0.​
By the relations of the DP array above, we can evaluate the DP array in descending order of i and j. We could find the answer using dpN, i, f =1 and dpi, N, f = 0 for i<W, we could find the answer.
Define a 3D DP array dpi, j, f where dpi, j, f is the probability that player 1 wins when player 1 is at position i and player 2 is at position j, and f is 0 if it’s player 1’s turn and 1 if it’s player 2’s turn.
Below are the steps involved in the implementation of the code:
- Initialize the DP array as follows:
- Set dpi, j, 0 = 1 if i = N and dpi, j, 1 = 0 if i = N.
- Set dpi, j, 0 = 0 if j = N and dpi, j, 1 = 1 if j = N.
- For all other values of i, j, and f, set dpi, j, f = -1 (to indicate that it hasn’t been computed yet).
- Evaluate the DP array in descending order of i and j, and for each f value (0 for player 1’s turn, 1 for player 2’s turn):
- If dpi, j, and f have already been computed, skip to the next value.
- If f = 0 (player 1’s turn), set dpi, j, 0 as follows:
- For k = 1 to A, compute the new position i’ = min(i + k, W).
- Compute the average of dpi’, j, 1 overall valid i’ values (i.e., i’ ≤ W).
- Set dpi, j, 0 = that average.
- If f = 1 (player 2’s turn), set dpi, j, 1 as follows:
- For k = 1 to B, compute the new position j’ = min(j + k, W).
- Compute the average of dpi, j’, 0 overall valid j’ values (i.e., j’ ≤ W).
- Set dpi, j, 1 = that average.
- The answer to the problem is dpi, j, 0, where i = 0 and j = 0.
Below are the steps involved in the implementation of the code:
C++
#include <iostream>
using namespace std;
const int MOD = 998244353;
int dp[110][110][2];
int mdp( int W, int x, int y, int A, int B)
{
for ( int i = 0; i <= W; i++) {
for ( int f = 0; f < 2; f++) {
dp[W][i][f] = 1;
dp[i][W][f] = 0;
}
}
for ( int i = W - 1; i >= 0; i--) {
for ( int j = W - 1; j >= 0; j--) {
for ( int k = 1; k <= A; k++) {
dp[i][j][0] += dp[min(W, i + k)][j][1];
}
dp[i][j][0] %= MOD;
dp[i][j][0] *= 1LL * (MOD - 1) / A;
dp[i][j][0] %= MOD;
for ( int k = 1; k <= B; k++) {
dp[i][j][1] += dp[i][min(W, j + k)][0];
}
dp[i][j][1] %= MOD;
dp[i][j][1] *= 1LL * (MOD - 1) / B;
dp[i][j][1] %= MOD;
}
}
return dp[x][y][0];
}
int main()
{
int W = 6, x = 3, y = 2, A = 5, B = 4;
cout << mdp(W, x, y, A, B);
return 0;
}
|
Java
class GFG {
static final int MOD = 998244353 ;
static int [][][] dp;
static int mdp( int W, int x, int y, int A, int B)
{
dp = new int [W + 1 ][W + 1 ][ 2 ];
for ( int i = 0 ; i <= W; i++) {
for ( int f = 0 ; f < 2 ; f++) {
dp[W][i][f] = 1 ;
dp[i][W][f] = 0 ;
}
}
for ( int i = W - 1 ; i >= 0 ; i--) {
for ( int j = W - 1 ; j >= 0 ; j--) {
for ( int k = 1 ; k <= A; k++) {
dp[i][j][ 0 ]
+= dp[Math.min(W, i + k)][j][ 1 ];
}
dp[i][j][ 0 ] %= MOD;
dp[i][j][ 0 ] *= (MOD - 1 ) / A;
dp[i][j][ 0 ] %= MOD;
for ( int k = 1 ; k <= B; k++) {
dp[i][j][ 1 ]
+= dp[i][Math.min(W, j + k)][ 0 ];
}
dp[i][j][ 1 ] %= MOD;
dp[i][j][ 1 ] *= (MOD - 1 ) / B;
dp[i][j][ 1 ] %= MOD;
}
}
return dp[x][y][ 0 ];
}
public static void main(String[] args)
{
int W = 6 , x = 3 , y = 2 , A = 5 , B = 4 ;
System.out.println(mdp(W, x, y, A, B));
}
}
|
C#
using System;
using System.Collections.Generic;
class Program {
static int MOD = 998244353;
static int [, , ] dp;
static int mdp( int W, int x, int y, int A, int B)
{
dp = new int [W + 1, W + 1, 2];
for ( int i = 0; i <= W; i++) {
for ( int f = 0; f < 2; f++) {
dp[W, i, f] = 1;
dp[i, W, f] = 0;
}
}
for ( int i = W - 1; i >= 0; i--) {
for ( int j = W - 1; j >= 0; j--) {
for ( int k = 1; k <= A; k++) {
dp[i, j, 0]
+= dp[Math.Min(W, i + k), j, 1];
}
dp[i, j, 0] %= MOD;
dp[i, j, 0] *= (MOD - 1) / A;
dp[i, j, 0] %= MOD;
for ( int k = 1; k <= B; k++) {
dp[i, j, 1]
+= dp[i, Math.Min(W, j + k), 0];
}
dp[i, j, 1] %= MOD;
dp[i, j, 1] *= (MOD - 1) / B;
dp[i, j, 1] %= MOD;
}
}
return dp[x, y, 0];
}
static void Main( string [] args)
{
int W = 6, x = 3, y = 2, A = 5, B = 4;
Console.WriteLine(mdp(W, x, y, A, B));
}
}
|
Time Complexity: O(W2 * A * B)
Auxiliary Space: O(W2)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...