Math
Compute gcd(a, b) = gcd(b, a mod b) recursively. Used for fraction reduction, coprimality checks, finding periods, and LCM via lcm(a,b) = a*b / gcd(a,b).
The greatest common divisor (GCD) of two integers is the largest positive integer that divides both without a remainder. It shows up constantly in competitive programming: simplifying fractions, checking whether two lengths can tile a rectangle, finding the period hidden inside a sequence. The Euclidean algorithm computes it in , fast enough that even calling it millions of times inside a loop is usually fine.
The algorithm rests on a single identity:
gcd(a, b) = gcd(b, a % b)Proof sketch: any divisor of both a and b must also divide a % b = a - floor(a/b)*b, so the set of common divisors is unchanged when you replace a with a % b. Repeating this replacement shrinks the numbers rapidly, since the remainder is always strictly less than the divisor, until the smaller value reaches zero, at which point the other value is the GCD.
Starting with 48 and 18:
gcd(48, 18): 48 % 18 = 12 → gcd(18, 12)gcd(18, 12): 18 % 12 = 6 → gcd(12, 6)gcd(12, 6): 12 % 6 = 0 → gcd(6, 0)gcd(6, 0): b is zero, return 6.So gcd(48, 18) = 6. Three steps to reduce two two-digit numbers. For 64-bit integers the algorithm never needs more than about 93 steps.
def gcd(a: int, b: int) -> int:
while b:
a, b = b, a % b
return aPython 3.5+ ships math.gcd, but knowing the implementation matters when you need to adapt it (e.g., extended GCD, or GCD over negative numbers where you want abs guards).
The LCM of two numbers is the smallest positive integer divisible by both. Trying to compute it directly by multiplying and dividing is fine for small values but overflows with large integers if you're not careful. The safe formula divides first:
lcm(a, b) = a // gcd(a, b) * bDividing a by gcd(a, b) before multiplying by b keeps intermediate values smaller.
def lcm(a: int, b: int) -> int:
return a // gcd(a, b) * bBoth operations are associative and commutative, so you can reduce an entire array pairwise. Python's functools.reduce handles this cleanly. The identity element for GCD is 0 (since gcd(0, x) = x for any positive x), which means you can safely fold over an empty prefix.
from math import gcd
from functools import reduce
def array_gcd(nums: list[int]) -> int:
return reduce(gcd, nums)
def array_lcm(nums: list[int]) -> int:
return reduce(lcm, nums)A useful trick: if array_gcd(nums) == 1, the numbers are coprime as a group. In problems about reachable sums or coin denominators, coprimality is often the condition that makes every sufficiently large integer reachable.
The standard Euclidean algorithm tells you the GCD. The extended version also tells you the integer coefficients x and y satisfying:
a*x + b*y = gcd(a, b)This is Bezout's identity. It's the foundation of modular inverse computation: if gcd(a, m) = 1, then the x returned by ext_gcd(a, m) is a's inverse modulo m.
def ext_gcd(a: int, b: int) -> tuple[int, int, int]:
"""Returns (g, x, y) such that a*x + b*y = g = gcd(a, b)."""
if b == 0:
return a, 1, 0
g, x, y = ext_gcd(b, a % b)
# Back-substitute: new x = old y, new y = old x - (a//b)*old y
return g, y, x - (a // b) * yTracing the recursion:
ext_gcd(48, 18) calls ext_gcd(18, 12)ext_gcd(18, 12) calls ext_gcd(12, 6)ext_gcd(12, 6) calls ext_gcd(6, 0) → returns (6, 1, 0)ext_gcd(12, 6): (6, 0, 1 - 2*0) = (6, 0, 1)ext_gcd(18, 12): (6, 1, 0 - 1*1) = (6, 1, -1)ext_gcd(48, 18): (6, -1, 1 - 2*(-1)) = (6, -1, 3)Check: 48*(-1) + 18*3 = -48 + 54 = 6. Correct.
When you need to divide inside a modular arithmetic expression, say, to compute (a / b) % p where p is prime, you need the modular inverse of b. The extended GCD gives it directly when gcd(b, p) = 1 (always true if p is prime and b is not a multiple of p):
def mod_inverse(b: int, p: int) -> int:
g, x, _ = ext_gcd(b % p, p)
if g != 1:
raise ValueError("Inverse does not exist")
return x % pPython 3.8+ also provides pow(b, -1, p) for the same result, but the extended GCD is more portable and instructive.
gcd(min, max). The full array reduce also works.s and t is the prefix of length gcd(len(s), len(t)), provided s + t == t + s.z liters with jugs of size x and y iff z is a multiple of gcd(x, y) and z \leq x + y, a direct consequence of Bezout's identity.p and q by their GCD before classifying which receptor is hit.gcd of a set of denominations is d, every sufficiently large multiple of d is representable (Chicken McNugget / Frobenius theorem).Each GCD call runs in time and, for the iterative version, space. The recursive extended GCD uses stack frames. Reducing an array of n numbers via pairwise GCD costs where is the maximum value.
You're probably looking at GCD / LCM / Euclidean algorithm when:
gcd(a, m) = 1.Common templates:
z is reachable iff gcd(x, y) divides z. Example: Water and Jug Problem.gcd(len(s), len(t)). Example: Greatest Common Divisor of Strings.ax + by = gcd(a, b) to invert under a modulus. Example: Number of Subarrays With GCD Equal to K.Practice Problems (21)