# 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; } ```