Hints — Module 02: Mathematical Preliminaries
Graduated hints, three per stage. Reach for hint 1 first; drop to 3 only when stuck.
Stage 1: Sums in closed form
- Every sum here has a closed form derived in §1.2.3 (Gauss pairing for the linear sum, the perturbation method for squares and the geometric series). Compute the formula directly in O(1) — never loop
kfrom 1 ton. - Use
n(n+1)/2,n(n+1)(2n+1)/6, and Nicomachus(n(n+1)/2)^2for the three power sums; for the geometric sum use(x^(n+1) - 1)/(x - 1)with a special case forx == 1. Widen tou128/i128before multiplying so the products don't overflow. sum_first_n:n*(n+1)/2inu128.sum_squares: formt = n*(n+1)/2first, thent*(2n+1)/3(each division is exact).sum_cubes:let t = sum_first_n(n); t*t.geometric_sum:if x == 1 { n+1 } else { (x.pow(n+1) - 1)/(x - 1) }.
Stage 2: Binomial coefficients
- Never compute
C(n,k)asn!/(k!(n-k)!)— the factorials overflow long before the answer does. Use the multiplicative recurrence of §1.2.6 Eq. (3), which keeps every partial result an honest integer. - Build the coefficient as a running product
c <- c*(n-k+i)/ifori = 1..=k. Because after stepithe value equalsC(n-k+i, i), each division lands exactly. Exploit the symmetryC(n,k) = C(n,n-k)to replacekwithmin(k, n-k), and return 0 whenk > n. if k > n { return 0; } let k = k.min(n-k);thenlet mut c: u128 = 1; for i in 1..=k { c = c*(n-k+i)/i; } c. Do the multiply before the divide so the intermediate is divisible.
Stage 3: Fibonacci numbers, fast
F_nis defined byF_0 = 0,F_1 = 1,F_{n+1} = F_n + F_{n-1}(§1.2.8). A single left-to-right pass keeping the last two values computes it in O(n) additions — no recursion, no memo table.- Carry a rolling pair
(a, b)equal to(F_{i-1}, F_i)and advance it. Guard the domain:F_186is the largest that fits inu128, so assertn <= 186(the test expects a panic containing "overflows" forn = 187). if n == 0 { return 0; } let (mut a, mut b) = (0u128, 1u128); for _ in 1..n { let t = a+b; a = b; b = t; } b. The assert message must contain the substringoverflows.
Stage 4: Harmonic numbers, exactly and asymptotically
H_n = 1 + 1/2 + ... + 1/nis rational; to keep it exact you must do fraction arithmetic and reduce by the gcd each step, or the denominator explodes. The floating version is a separate, approximate computation (§1.2.7).- For the exact form keep a reduced
(num, den); adding1/kgives(num*k + den)/(den*k), then divide both by their gcd. Forharmonic_f64, sum the reciprocals from the smallest term upward so rounding error stays a few ulps. - Exact:
num = num*k + den; den *= k; let g = gcd(num, den); num /= g; den /= g;loopingkin1..=n, starting(0, 1). Float:for k in (1..=n).rev() { h += 1.0/k as f64; }. You'll need a smallu128gcd helper (Euclid again).
Stage 5: Analysis of an algorithm: finding the maximum
- Algorithm 1.2.10M scans the array and tracks both the running maximum and the count
Aof times it was updated. That count is the quantity §1.2.10 analyzes; its expectation on a random permutation of distinct values isH_n - 1, tying this stage back to Stage 4. - Follow Knuth's steps: initialize with the last element as the max at index
n, then scankdownward; replace the max only on a strict increase (M4), which makes ties keep the rightmost index. Return(j, m, a)withjconverted to 0-based. let mut j = n; let mut k = n-1; let mut m = xs[n-1]; let mut a = 0;thenloop:if k == 0 { return (j-1, m, a); };if xs[k-1] > m { j = k; m = xs[k-1]; a += 1; };k -= 1;. The plainfind_maxjust dropsafrom the triple.