GCD, LCM, and Euclid's Algorithm - Preparation to IOI Part 1
Number Theory
GCD, LCM, and Euclid's Algorithm
GCD, LCM, and Euclid's Algorithm
Назария
Дарси 1 аз 1
Хониш: 8 дақиқа
Greatest common divisor
Throughout this lesson, all inputs are nonnegative integers.
The greatest common divisor, gcd(a,b), is the largest positive integer dividing both a and b, provided at least one is nonzero.
Every positive integer divides zero. Therefore, when a>0, the common divisors of a and are exactly the divisors of , giving . We also set by convention; in that case, there is no largest positive common divisor.
We can reduce the numbers without changing their common divisors. For b>0, divide a by b and write a=qb+r, where q is the quotient and 0≤r<b is the remainder.
Any number dividing both a and b also divides r=a−qb. Conversely, any number dividing both b and r divides a=qb+r. Thus the pairs (a,b) and (b,r) have exactly the same common divisors:
gcd(a,b)=gcd(b,amodb).
Euclid's algorithm repeatedly applies this replacement. Each new second argument is smaller than the previous one, so eventually it becomes zero. The first argument is then the answer.
The diagram follows the pair (84,30). Each row splits the first number into complete copies of the second number and a remainder. The blue remainder becomes the second argument in the next row.
Интерактивсанҷида бин!
Why the algorithm is fast
The second argument need not halve in one step: above, it first decreases from 30 to 24. However, it at least halves within two steps.
If a<b, the first step swaps the two numbers. Once a≥b>0, let r=amodb:
If r≤b/2, the first step already gives the required decrease.
If r>b/2, then r<b<2r, so the next remainder is bmodr=b−r<b/2.
The algorithm therefore uses O(log(2+min(a,b))) remainder operations, including the zero-input cases.
Check your reasoning
It preserves the GCD: when a>b, the pairs (a,b) and (a−b,b) have the same common divisors. The other case is symmetric. Both numbers stay positive and their sum decreases, so the process reaches equal numbers; their common value is the original GCD.
The iteration bound is different. Starting with (m,1) requires m−1 subtractions. Euclid's remainder operation removes all complete copies at once, so it finishes this case in one step.
Least common multiple
While the GCD measures shared divisors, the least common multiple, lcm(a,b), is the smallest positive integer divisible by both positive inputs. If either input is zero, we define the LCM to be zero, including lcm(0,0)=0.
To relate the two operations, consider prime factorization. A prime is an integer at least 2 with no positive divisors other than 1 and itself. Every positive integer has a unique prime factorization; 1 has no prime factors.
For a prime p, let αp and βp be its exponents in a and b, using zero when p is absent. A common divisor can contain at most min(αp,βp) copies of p, and the GCD uses exactly that many. A common multiple needs at least max(αp,βp) copies, and the LCM uses exactly that many.
Multiplying the GCD and LCM adds these exponents. Since their sum is αp+βp for every prime, the product is ab. Hence, for positive a,b,
lcm(a,b)=gcd(a,b)ab.
Avoiding overflow
Compute the division before the multiplication. The product ab might overflow even when the LCM fits, whereas a/gcd(a,b) is an integer no larger than a.
The final product can still be too large. Let M be the largest value of long long, given by LLONG_MAX, and set x=a/gcd(a,b). For b>0, multiplying x by b is safe exactly when
x≤⌊bM⌋.
Check this inequality before multiplying. Handle zero inputs first so that neither this check nor the GCD division can divide by zero.
GCD and LCM of a list
Both operations are associative: grouping the elements differently does not change the answer. A number divides every element exactly when it divides their GCD, and a number is a common multiple of every element exactly when it is a multiple of their LCM. These descriptions do not depend on grouping. The zero conventions preserve associativity as well.
For the GCD of a nonempty list a1,…,an, start with g=0 and process each element using
g←gcd(g,ai).
The initial zero works because gcd(0,ai)=ai. Once g=1, further elements cannot change it.
For the LCM, first check whether the list contains zero. If it does, the answer is zero. Otherwise, start with ℓ=1 and repeatedly combine ℓ with the next element, checking for overflow each time. Every new LCM is a positive multiple of the previous one. Therefore, if a partial result exceeds the limit, the final result must also exceed it.
Checking for zero first is essential when stopping at the first overflow: a zero later in the list would make the final answer zero instead.
Check your reasoning
Take a=6, b=10, and c=15. Their GCD is 1, but their LCM is 30, whereas abc=900. No prime divides all three numbers, yet each prime factor is shared by a pair.
The equality holds exactly when every pair has GCD 1: the numbers are pairwise coprime. If their prime factors are disjoint, the largest exponent of each prime equals its exponent in the product. If a prime divides two numbers, its exponent in the product is strictly greater than its largest exponent in any one number, so the product exceeds the LCM.
C++ Implementation
Both arguments must fit in long long and be nonnegative. The function lcm_safe returns −1 if the LCM exceeds LLONG_MAX.
Show implementation
You will learn
Compute the GCD using Euclid's algorithm and explain why each step preserves the answer.
Prove the LCM formula using prime factorizations.
Compute an LCM while checking for 64-bit overflow.
Combine GCD and LCM over a list, including lists containing zero.
Activity
For positive a and b, consider repeatedly subtracting the smaller number from the larger one until they become equal. Does this procedure preserve the GCD? Does it have the same logarithmic bound on the number of iterations? Justify both answers.
Think again
Let a,b,c be positive integers with gcd(a,b,c)=1. Must ? If not, construct a counterexample. Find the exact condition on the three pairwise GCDs that makes the equality hold.
lcm(a,b,c)=abc
#include <bits/stdc++.h>using namespace std;long long gcd(long long a, long long b){ while(b > 0){ long long r = a % b; a = b; b = r;} return a;}long long lcm_safe(long long a, long long b){ if(a == 0 || b == 0){ return 0;} a /= gcd(a, b); if(a > LLONG_MAX / b){ return -1;} return a * b;}