Skip to main content

Number Theory

Divisors

A huge number of problems boil down to: “loop i=1ni = 1 \dots \lfloor \sqrt{n}\rfloor and use the factor pair (i,n/i)(i, n/i).”

Enumerating all divisors (divisor pairs)

Key idea:

  • If ini \mid n, then both ii and ni\frac{n}{i} are divisors. In every divisor pair, one of the numbers must be less than or equal to n\sqrt{n}.
  • Therefore, we only need to check ini \le \sqrt{n}.

Make sure to avoid double-counting when i2=ni^2 = n.

Practice:


Some useful divisor formulas:

For smaller values of nn these can often be done naively, however these are still useful to know: If n=piein = \prod p_i^{e_i}, then:

τ(n)\tau(n), σ(n)\sigma(n), and P(n)P(n) represent the number, sum, and product of divisors of nn respectively.

τ(n)=(ei+1)\tau(n) = \prod (e_i + 1) σ(n)=piei+11pi1\sigma(n) = \prod \frac{p_i^{e_i+1}-1}{p_i-1} P(n)=nτ(n)2P(n) = n^{\frac{\tau(n)}{2}}

Sieve of Eratosthenes

When constraints involve many queries or large ranges, factoring by n\sqrt{n} 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 O(nlog(logn))O(n\log(\log n)).

Notes:

  • Start marking at p2p^2 (smaller multiples were marked earlier). In some variations, you may need to start from 2p2p, but this doesnt change the asymptotics of sieve.
  • Use this when you need primality for all numbers up to NN.

Practice:


SPF sieve (smallest prime factor) for fast factorization

Goal: precompute spf[x] = smallest prime dividing x. Then each factorization is O(logx)O(\log x) 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 O(# of divisors)O(\text{\# of divisors}) instead of O(n)O(\sqrt{n}), 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 dd, look at all multiples k=d,2d,3d,k = d, 2d, 3d, \dots
for d in 1..N:
for k in d, 2d, 3d, ..., <= N:
// do something with (d divides k)

If the inner computation is O(1)O(1), this has time complexity O(nlogn)O(n\log n).

Let's revisit: Counting Divisors (CSES)

Practice:


Problems


GCD / LCM

Core identities

  • Euclidean Algorithm:
gcd(a,b)=gcd(b, a mod b)\gcd(a,b) = \gcd\bigl(b,\ a \text{ mod } b\bigr)
  • LCM via gcd:
lcm(a,b)=agcd(a,b)b\mathrm{lcm}(a,b) = \frac{a}{\gcd(a,b)} \cdot b

Implementation note: compute as (a / gcd(a,b)) * b to reduce overflow risk.


LCM/GCD via prime exponents

To compute lcm(a1,,an)\mathrm{lcm}(a_1,\dots,a_n) (especially under a modulus), you often:

  1. factor all numbers
  2. keep the maximum exponent of each prime
  3. rebuild the lcm as pmaxep\prod p^{\max e_p} (optionally modulo MM)

Similarly for gcd\gcd you may take the minimum exponent of each prime.

Practice:


Problems: