Number Theory
Divisors
A huge number of problems boil down to: “loop and use the factor pair .”
Enumerating all divisors (divisor pairs)
Key idea:
- If , then both and are divisors. In every divisor pair, one of the numbers must be less than or equal to .
- Therefore, we only need to check .
Make sure to avoid double-counting when .
Practice:
- Counting Divisors (CSES) (may need to be careful with your implementation to avoid TLE)
- Common Divisors(CSES)
- kth divisor (CF)
- Secret Message (recent CF div 2)
- Division or Subtraction (AC)
- Tonya and Burenka-179 (CF)
Some useful divisor formulas:
For smaller values of these can often be done naively, however these are still useful to know: If , then:
, , and represent the number, sum, and product of divisors of respectively.
Sieve of Eratosthenes
When constraints involve many queries or large ranges, factoring by per query is too slow. The sieve family lets you precompute prime/primality/least-prime-factor in very close to linear time.
Classic Sieve (primality)
is_prime[0]=is_prime[1]=false
is_prime[2..N]=true
for p in 2..floor(sqrt(N)):
if is_prime[p]:
for x in p*p, p*p+p, ..., <= N:
is_prime[x]=false
The time complexity is .
Notes:
- Start marking at (smaller multiples were marked earlier). In some variations, you may need to start from , but this doesnt change the asymptotics of sieve.
- Use this when you need primality for all numbers up to .
Practice:
SPF sieve (smallest prime factor) for fast factorization
Goal: precompute spf[x] = smallest prime dividing x.
Then each factorization is by repeated division.
spf[1]=1
for i in 2..N:
if spf[i]==0: // i is prime
spf[i]=i
for j in i*i, i*i+i, ..., <= N:
if spf[j]==0:
spf[j]=i
Note that from the prime factorization, you can find all divisors in instead of , which can be relevant sometimes.
Use cases:
- many factorizations
- counting prime exponents / computing divisor counts for many numbers
You can even compute totients for all numbers with sieve.
“Sieve over values” (iterate multiples)
This pattern is not about primality; it’s about counting multiples efficiently:
- for each value , look at all multiples
for d in 1..N:
for k in d, 2d, 3d, ..., <= N:
// do something with (d divides k)
If the inner computation is , this has time complexity .
Let's revisit: Counting Divisors (CSES)
Practice:
- Not Divisible (AtCoder ABC170 D)
- Common Divisors (CSES) - (Can we find a better time complexity than before?)
- Turn on the Light 3
Problems
GCD / LCM
Core identities
- Euclidean Algorithm:
- LCM via gcd:
Implementation note: compute as (a / gcd(a,b)) * b to reduce overflow risk.
LCM/GCD via prime exponents
To compute (especially under a modulus), you often:
- factor all numbers
- keep the maximum exponent of each prime
- rebuild the lcm as (optionally modulo )
Similarly for you may take the minimum exponent of each prime.
Practice:
Problems: