---
# System prepended metadata

title: 'JudgeGirl #235'
tags: [pachinko, dynamic-programming, judgegirl]

---

# JudgeGirl #235

## Pachinko

Basically there are `i+1` pins on the i-th row, and different amount of balls fall down to each side, called bucket. Calculate the probability that a ball falls into each N+1 bucket. **N <= 15**
![](https://hackmd.io/_uploads/rk6UF4jlp.jpg)

For the above example: 
2/15 = 1/3 * 2/5, 7/10 = 1/3\*5/3 + 3/2\*4/3

**Hint:** In order to prevent arithmetic overflow, you should reduce the denominator and numerator of each fractional number you use.

## Keys

### 1. The Fraction Structure

It is pretty straight forward that we implement a fraction struct, otherwise it's quite hideous to store a fraction.
```c
typedef long long ll;
typedef struct {
    ll up, down; // ll so we don't overflow
                 // up is num, down is denum
} Frac;
```

### 2. gcd()

It is also obvious that we need a `gcd()` function in order to reduce the fraction. [About the Euclidean algorithm](https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/the-euclidean-algorithm).
```c
ll gcd(ll a, ll b) {
    ll temp;
    while (b != 0) {
        temp = a % b;
        a = b;
        b = temp;
    }
    return a;
}
```

### 3. The Pins Array

We need to find a way to store all the fraction the problem gives us. 
The way we store them is that the j-th pin on the i-th row will be `pins[i][j]`. 
The problem says that N is no more than 15, so an array of `pins[20][20]` is more than enough. (there will only be 16 pins on the 15th row)

Also notice that we only need to store one fraction `p` in each pin, we can get the other one by `1 - p`.
```c
ll left, right;
for (int i = 0; i < n; i++) {
    for (int j = 0; j <= i; j++) { // the i-th row has i pins
        scanf("%lld %lld", &left, &right);
        right = left + right;
        ll g = gcd(left, right);
        left /= g, right /= g;
        pins[i][j].up = left, pins[i][j].down = right;
    }
}
```
**Note:** reduce the fraction first, then store.

### 4. The Buckets

To understand the problem better, we can draw a simple graph:

![](https://hackmd.io/_uploads/rygL0Taie6.jpg)

So we construct another array of `dp[20][20]` as the buckets, and we set `dp[0][0]` to one (fractional 1).
Then we notice that the `pins[i][j]` will always falls into `dp[i+1][j]`, and 1 - `pins[i][j]` always falls into `dp[i+1][j+1]`.

```c
// set dp to all fractional zero so when we do addition it won't fuck up.
for (int i = 0; i < M; i++) 
    for (int j = 0; j < M; j++) 
        {dp[i][j].up = 0, dp[i][j].down = 1;}

// set first bucket to fraction one.
dp[0][0].up = 1, dp[0][0].down = 1;
for (int i = 0; i < n; i++) {
    for (int j = 0; j <= i; j++) {
        // muliply last bucket with pins[i][j]
        ll lastup = dp[i][j].up, lastdown = dp[i][j].down;
        ll thisup = pins[i][j].up, thisdown = pins[i][j].down;
        thisup *= lastup, thisdown *= lastdown;
        ll g = gcd(thisup, thisdown);
        thisup /= g, thisdown /= g;
        // add result to this bucket
        ll a = dp[i+1][j].up * thisdown + dp[i+1][j].down * thisup, b = dp[i+1][j].down * thisdown;
        g = gcd(a, b);
        a /= g, b /= g;
        dp[i+1][j].up = a, dp[i+1][j].down = b;
        // following are same but with 1 - pins[i][j]
        // multiply
        thisup = pins[i][j].down - pins[i][j].up, thisdown = pins[i][j].down;
        thisup *= lastup, thisdown *= lastdown;
        g = gcd(thisup, thisdown);
        thisup /= g, thisdown /= g;
        // add
        a = dp[i+1][j+1].up * thisdown + dp[i+1][j+1].down * thisup, b = dp[i+1][j+1].down * thisdown;
        g = gcd(a, b);
        a /= g, b /= g;
        dp[i+1][j+1].up = a, dp[i+1][j+1].down = b;
    }
}
```

Finally, the last row we did is `n - 1`, so `dp[n]` will have our answer.

## Code

```c
#include <stdio.h>

#define M 20

typedef long long ll;

ll gcd(ll a, ll b) {
    ll temp;
    while (b != 0) {
        temp = a % b;
        a = b;
        b = temp;
    }
    return a;
}

typedef struct {
    ll up, down;
} Frac;

Frac pins[M][M], dp[M][M];

int main() {
    int n;
    scanf("%d", &n);

    ll left, right;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= i; j++) {
            scanf("%lld %lld", &left, &right);
            right = left + right;
            ll g = gcd(left, right);
            left /= g, right /= g;
            pins[i][j].up = left, pins[i][j].down = right;
        }
    }

    for (int i = 0; i < M; i++) for (int j = 0; j < M; j++) {dp[i][j].up = 0, dp[i][j].down = 1;}
    dp[0][0].up = 1, dp[0][0].down = 1;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= i; j++) {
            // mul
            ll lastup = dp[i][j].up, lastdown = dp[i][j].down;
            ll thisup = pins[i][j].up, thisdown = pins[i][j].down;
            thisup *= lastup, thisdown *= lastdown;
            ll g = gcd(thisup, thisdown);
            thisup /= g, thisdown /= g;
            // add
            ll a = dp[i+1][j].up * thisdown + dp[i+1][j].down * thisup, b = dp[i+1][j].down * thisdown;
            g = gcd(a, b);
            a /= g, b /= g;
            dp[i+1][j].up = a, dp[i+1][j].down = b;
            // mul
            thisup = pins[i][j].down - pins[i][j].up, thisdown = pins[i][j].down;
            thisup *= lastup, thisdown *= lastdown;
            g = gcd(thisup, thisdown);
            thisup /= g, thisdown /= g;
            // add
            a = dp[i+1][j+1].up * thisdown + dp[i+1][j+1].down * thisup, b = dp[i+1][j+1].down * thisdown;
            g = gcd(a, b);
            a /= g, b /= g;
            dp[i+1][j+1].up = a, dp[i+1][j+1].down = b;
        }
    }

    for (int i = 0; i <= n; i++) printf("%lld/%lld\n", dp[n][i].up, dp[n][i].down);



    return 0;
}

```