Math, Algorithms, and Code
A collection of interesting mathematical concepts and their implementations.
The content here was pulled from the internet to test KaTeX and markdown rendering on this site. Math is now rendered server-side via the
katexRust crate. No client-side JS, no layout shift.
The Sieve of Eratosthenes
One of the oldest algorithms still in use. Given an upper bound n, it finds all prime numbers up to n by iteratively marking composites.
Time complexity: . Space: .
fn sieve(n: usize) -> Vec<bool> { let mut is_prime = vec![true; n + 1]; is_prime[0] = false; is_prime[1] = false; let mut i = 2; while i * i <= n { if is_prime[i] { let mut j = i * i; while j <= n { is_prime[j] = false; j += i; } } i += 1; } is_prime }
The key insight: you only need to sieve up to . Every composite number has a prime factor . For that means only checking up to .
Fast Exponentiation
Computing naively takes multiplications. Binary exponentiation does it in by exploiting:
- If is even:
- If is odd:
fn power(mut base: u64, mut exp: u64, modulus: u64) -> u64 { let mut result = 1u64; base %= modulus; while exp > 0 { if exp % 2 == 1 { result = result * base % modulus; } exp /= 2; base = base * base % modulus; } result }
This is the backbone of RSA encryption. Computing where can be or larger. Impossible without this trick.
The Birthday Paradox
In a room of just 23 people, there’s a >50% chance two share a birthday. The probability that all birthdays are distinct:
def birthday_probability(n): p = 1.0 for i in range(n): p *= (365 - i) / 365 return 1 - p # birthday_probability(23) ≈ 0.5073 # birthday_probability(50) ≈ 0.9704 # birthday_probability(70) ≈ 0.9992
This matters in cryptography. A hash function with 128-bit output doesn’t need attempts to find a collision, only about (the square root). This is why SHA-256 provides 128-bit collision resistance, not 256-bit.
Fibonacci via Matrix Exponentiation
The naive recursive Fibonacci is . Dynamic programming gets it to . But matrix exponentiation computes in :
type Matrix = [[u64; 2]; 2]; fn multiply(a: &Matrix, b: &Matrix, m: u64) -> Matrix { let mut c = [[0u64; 2]; 2]; for i in 0..2 { for j in 0..2 { for k in 0..2 { c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % m; } } } c } fn matrix_power(mut base: Matrix, mut n: u64, m: u64) -> Matrix { let mut result: Matrix = [[1, 0], [0, 1]]; // identity while n > 0 { if n % 2 == 1 { result = multiply(&result, &base, m); } base = multiply(&base, &base, m); n /= 2; } result } fn fibonacci(n: u64, m: u64) -> u64 { if n == 0 { return 0; } let base: Matrix = [[1, 1], [1, 0]]; let result = matrix_power(base, n, m); result[0][1] }
Computing ? No problem. Try that with a loop.
Euclidean Algorithm
The GCD algorithm is ancient (circa 300 BC) and still one of the most useful:
fn gcd(mut a: u64, mut b: u64) -> u64 { while b != 0 { let t = b; b = a % b; a = t; } a }
The extended version finds such that :
fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) { if b == 0 { return (a, 1, 0); } let (g, x1, y1) = extended_gcd(b, a % b); (g, y1, x1 - (a / b) * y1) }
This gives you modular inverses for free. If , then the from is the modular inverse of . Essential for division in modular arithmetic.
Reservoir Sampling
Select items uniformly at random from a stream of unknown length. You see each element once and can’t go back.
import random def reservoir_sample(stream, k): reservoir = [] for i, item in enumerate(stream): if i < k: reservoir.append(item) else: j = random.randint(0, i) if j < k: reservoir[j] = item return reservoir
The proof is elegant: at step (0-indexed), each of the first elements has probability of being in the reservoir. By induction, when the stream ends at length , each element has probability of being selected. Uniform.
Euler’s Totient Function
counts integers from to that are coprime to . For prime : . For prime powers: . The function is multiplicative: when .
fn euler_totient(mut n: u64) -> u64 { let mut result = n; let mut p = 2; while p * p <= n { if n % p == 0 { while n % p == 0 { n /= p; } result -= result / p; } p += 1; } if n > 1 { result -= result / n; } result }
Euler’s theorem: when . Fermat’s little theorem is the special case where is prime. This is why RSA works: decryption undoes encryption because .
Most of competitive programming boils down to recognizing which of these building blocks to reach for. The math hasn’t changed in centuries. The implementations fit in a few lines. Elegance is compression.