1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use cmp;
use env;
use fs;
use Path;
// We want to precompute a table for binomial coefficients ahead of
// time, since computing them on the fly is expensive. First, we
// can build the table using the recurrence:
//
// B(n, n) = 1
// B(n, k) = B(n - 1, k - 1) + B(n - 1, k)
//
// Here's the first few rows, where n is the row number (starting at zero), and
// k is the column number (also starting at zero).
//
// 1
// 1 1
// 1 2 1
// 1 3 3 1
// 1 4 6 4 1
// ...
//
// We can concatenate the rows into a flat array. Then, computing B(n, k)
// involves finding the start of the nth row, and then looking up the kth
// element in that row. The ith row has length i + 1, so then the nth row starts
// at 1 + 2 + ... + n, which is n * (n + 1) / 2.
//
// However, note that each row in the table above is symmetric: B(n, k) =
// B(n, n - k). So, we can cut our space usage in half by only storing the
// first half of each row.
//
// 1
// 1
// 1 2
// 1 3
// 1 4 6
// ...
//
// We need to be able to compute the length of a row and also efficiently compute
// the beginning of each row in our array, the sum of the previous rows' lengths.
// Previously, row i had length i + 1, and now it has length ceil((i + 1) / 2).
// We can then use the identity `ceil((n + 1) / m) = floor(n / m) + 1` to
// simplify this to `i // 2 + 1`, where `//` is integer division.
//
// Then, the start of row `n` is `\sum_{i=0}^{n-1} {i // 2 + 1}`, which we'd
// like to reduce to something closed-form. Here's the first few values:
//
// n: 0 1 2 3 4 5 ...
// row_len: 1 1 2 2 3 3 ...
// row_start: 0 1 2 4 6 9 ...
//
// Let's assume `n` is even. Then, note that summing the `row_len`s to the left
// is just `2 * (1 + 2 + ... + n/2)`. Then, we have
//
// row_start(2m) = 2 * (1 + 2 + ... + m)
// = 2 * m * (m + 1) / 2
// = m * (m + 1)
//
// Then, if `n` is odd, we need to add `row_len(n - 1)`
//
// row_start(2m + 1) = m * (m + 1) + row_len(2m)
// = m * (m + 1) + (m + 1)
// = (m + 1) * (m + 1)
//
// Now, we can combine the two cases:
//
// row_start(n) = (n / 2 + n % 2) * (n / 2 + 1)
//