Arithmetic functions and the Dirichlet convolution turn most divisor identities into one-line algebra. A function is multiplicative if and for coprime (completely multiplicative: for all ); it is then determined by its values on prime powers and can be sieved in (Sieves). Sums up to use the harmonic lemma and Du’s sieve (Floor Sums, Sublinear Sieves).
| Function | Definition | Type | |
|---|---|---|---|
| (identity of ) | completely multiplicative | ||
| completely multiplicative | |||
| completely multiplicative | |||
| multiplicative | |||
| if squarefree, else 0 | if , if | multiplicative | |
| number of divisors | multiplicative | ||
| multiplicative | |||
| , | distinct prime factors / with multiplicity | / | additive |
| product of the distinct primes | multiplicative | ||
| aliquot sum (proper divisors) | — | — |
The Dirichlet algebra
| Identity | Meaning |
|---|---|
| , | divisor count and sum |
| power sums of divisors | |
| Möbius inversion | |
| ”over multiples” inversion | |
| gcd sum | |
| coprime residue sum | for |
| small facts | even for ; ( even), ( odd) |
Proof: the algebra, and the main identities
Convolution is commutative and associative (both sides of sum over ), is the identity, and the convolution of multiplicative functions is multiplicative (divisors of with factor uniquely as , , ). : both multiplicative, and on () the sum is . Hence Möbius inversion: , and conversely. The “multiples” form is the same argument on the divisibility order reversed (or Möbius inversion on the poset, Inclusion–Exclusion). : classify by : then ranges over the residues coprime to , so the class has elements and the classes sum to ; inversion gives , and evaluating the multiplicative function on prime powers gives , hence . gcd sum: the same classification weights each class by . Coprime residues: pairs the coprime residues (), each pair summing to . Evenness: for the pairing has no fixed point ( is not coprime to ). follows from multiplicativity and for .
Computing , , ,
ll phiOf(ll n) { // O(sqrt n)
ll r = n;
for (ll p = 2; p * p <= n; p++) if (n % p == 0) { while (n % p == 0) n /= p; r -= r / p; }
if (n > 1) r -= r / n;
return r;
}
vector<int> phiUpTo(int n) { // O(n log log n); the linear sieve gives O(n)
vector<int> ph(n + 1); iota(all(ph), 0);
for (int i = 2; i <= n; i++) if (ph[i] == i) for (int j = i; j <= n; j += i) ph[j] -= ph[j] / i;
return ph;
}
vector<int> muUpTo(int n) { // O(n log n) via mu * 1 = eps
vector<int> mu(n + 1); if (n >= 1) mu[1] = 1;
for (int i = 1; i <= n; i++) for (int j = 2 * i; j <= n; j += i) mu[j] -= mu[i];
return mu;
}
template <class T> vector<T> dirichlet(const vector<T>& f, const vector<T>& g) { // (f * g)(1..n), O(n log n)
int n = sz(f) - 1; vector<T> h(n + 1);
for (int i = 1; i <= n; i++) for (int j = i, k = 1; j <= n; j += i, k++) h[j] += f[i] * g[k];
return h;
}Divisor count and sum for all : loop over multiples (Sieves); for one , factor and use the product formulas, or enumerate divisors from the factorisation (Factorization).
| max | 32 (840) | 240 (720 720) | 1344 (735 134 400) | 6720 | 103 680 |
Average order: , , and (the density of coprime pairs is ).
Counting with and
The workhorse: ; swap the order of summation and group equal values of (at most blocks).
| Quantity | Formula |
|---|---|
| coprime pairs | |
| pairs with | the same with , |
| , | |
| squarefree numbers | |
| fractions in lowest terms , (Farey length) | |
| lattice points visible from the origin in | |
| integers divisible by none of | inclusion–exclusion over subsets = restricted to those primes |
| ordered pairs with , | if , else 0 |
| blocks: | |
| hyperbola method |
ll coprimePairs(ll n, ll m, const vector<ll>& preMu) { // preMu[x] = sum_{d <= x} mu(d), x >= min(n, m)
ll res = 0;
for (ll l = 1, r; l <= min(n, m); l = r + 1) { r = min(n / (n / l), m / (m / l)); res += (preMu[r] - preMu[l - 1]) * (n / l) * (m / l); }
return res;
}
ll sumSigmaMod(ll n, ll M) { // sum_{i <= n} sigma(i) mod M = sum_d d * floor(n/d)
auto tri = [&](ll a, ll b) { i128 s = (i128)(a + b) * (b - a + 1) / 2; return (ll)(s % M); }; // a + ... + b
ll res = 0;
for (ll l = 1, r; l <= n; l = r + 1) { r = n / (n / l); res = (res + (i128)tri(l, r) * ((n / l) % M)) % M; }
return res;
}
ll gcdLcmPairs(ll X, ll Y) { // ordered (a, b) with gcd X and lcm Y
if (Y % X) return 0;
ll q = Y / X, c = 0; // primes where the exponents differ are those of Y / X
for (ll p = 2; p * p <= q; p++) if (q % p == 0) { c++; while (q % p == 0) q /= p; }
if (q > 1) c++;
return 1LL << c;
}Proof: coprime pairs, gcd / lcm sums, squarefree count, hyperbola, gcd–lcm pairs
Coprime pairs: . gcd sum: by , then swap sums. lcm sum: write , set with , remove the coprimality with and substitute , . Squarefree: (multiplicative check on : for , for ); sum over . Blocks: for , is constant for , and there are at most distinct values (either or the value is ). Hyperbola: counts lattice points ; count those with or and subtract the doubly counted square. : . gcd–lcm: prime by prime, , which gives 2 choices when the exponents differ and 1 when equal, and is necessary.
Euler’s theorem and power towers
for , so exponents reduce modulo (or the Carmichael ). Without coprimality, for : . Power towers recurse on , which reaches 1 within steps.
pair<ll, bool> powCap(ll a, ll e, ll m) { // {a^e mod m, a^e >= m}
ll r = 1 % m; bool big = false; ll x = a % m; bool xbig = a >= m;
for (; e; e >>= 1) {
if (e & 1) { big = big || xbig || (i128)r * x >= m; r = (i128)r * x % m; } // conservative flag
if (e > 1) { xbig = xbig || (i128)x * x >= m; x = (i128)x * x % m; }
}
return {r, big};
}
pair<ll, bool> tower(const vector<ll>& a, int i, ll m) { // a[i]^(a[i+1]^...) mod m, flag: value >= m
if (i == sz(a)) return {1 % m, 1 >= m};
if (m == 1) { auto [_, b] = tower(a, i + 1, 1); (void)_; return {0, true}; }
ll ph = phiOf(m); auto [e, ebig] = tower(a, i + 1, ph);
if (ebig) e += ph; // generalized Euler: only when the true exponent is >= phi
auto [v, vbig] = powCap(a[i], e, m);
return {v, vbig || (ebig && a[i] >= 2)};
}The “big” flags are needed because the shift by is only valid when the true exponent is large; with exponent below the plain value must be used. (A simpler, common bound: treat the exponent as large when the tower above has at least one element and the partial value exceeds .)
Proof: the generalised Euler theorem
Write and fix . If , Euler gives , and , so both sides agree modulo . If , then whenever , and both exponents qualify: , and . CRT combines the prime powers. The chain halves at least every two steps ( is even for and for even ), so the recursion depth is .
Prefix sums for huge : Du’s sieve
If and prefix sums of and are easy, then satisfies . Sieve up to and memoise the rest: .
| Target | ||
|---|---|---|
| Mertens | : | |
| : | ||
| : |
struct DuSieve { // Phi(n) = sum phi, M(n) = sum mu, n up to ~1e11 (values mod 2^64 for Phi)
int L; vector<ll> sphi, smu; unordered_map<ll, ll> cphi, cmu;
DuSieve(ll nmax) {
L = max(10, (int)cbrtl((long double)nmax * nmax)); sphi.assign(L + 1, 0); smu.assign(L + 1, 0);
vector<int> ph(L + 1), mu(L + 1), pr; vector<char> comp(L + 1); ph[1] = mu[1] = 1;
for (int i = 2; i <= L; i++) {
if (!comp[i]) pr.push_back(i), ph[i] = i - 1, mu[i] = -1;
for (int p : pr) { if ((ll)i * p > L) break; comp[i * p] = 1; if (i % p == 0) { ph[i * p] = ph[i] * p; mu[i * p] = 0; break; } ph[i * p] = ph[i] * (p - 1); mu[i * p] = -mu[i]; }
}
for (int i = 1; i <= L; i++) sphi[i] = sphi[i - 1] + ph[i], smu[i] = smu[i - 1] + mu[i];
}
ll Phi(ll n) {
if (n <= L) return sphi[n];
if (auto it = cphi.find(n); it != cphi.end()) return it->second;
ll r = (ll)((i128)n * (n + 1) / 2);
for (ll l = 2, rr; l <= n; l = rr + 1) { rr = n / (n / l); r -= (rr - l + 1) * Phi(n / l); }
return cphi[n] = r;
}
ll M(ll n) {
if (n <= L) return smu[n];
if (auto it = cmu.find(n); it != cmu.end()) return it->second;
ll r = 1;
for (ll l = 2, rr; l <= n; l = rr + 1) { rr = n / (n / l); r -= (rr - l + 1) * M(n / l); }
return cmu[n] = r;
}
};Proof: Du's recurrence and its cost
; isolate the term. Only values are ever requested (and ), so there are distinct states. A state costs by blocks; summing over for gives , and the sieve costs ; balancing at gives .
Patterns
| Problem | Approach |
|---|---|
| count numbers with exactly divisors | sieve ; or enumerate exponent signatures with |
| smallest number with at least divisors / highly composite numbers | DFS over non-increasing exponents of the first primes |
| number of divisors of a product / of | add exponents; Legendre per prime (Factorials mod p) |
| sum over pairs | iterate multiples, |
| order of , primitive roots | order divides (Primitive Roots) |
| necklaces with colours | (Burnside) |
| period of the decimal expansion of | multiplicative order of 10 modulo (after removing factors 2, 5) |
| inverse modulo composite | , but extended Euclid is simpler |
ll smallestWithDivisors(ll k) { // smallest n with d(n) >= k (k up to ~1e5; n fits in ll)
static const int P[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
ll best = LLONG_MAX;
auto dfs = [&](auto& self, int i, ll n, ll d, int maxE) -> void {
if (d >= k) { best = min(best, n); return; }
if (i == 16) return;
ll x = n;
for (int e = 1; e <= maxE; e++) { if ((i128)x * P[i] >= best) break; x *= P[i]; self(self, i + 1, x, d * (e + 1), e); }
};
dfs(dfs, 0, 1, 1, 62);
return best;
}Proof: exponents are non-increasing in the optimum
If has for primes , swapping the two exponents keeps and makes smaller. So a minimal uses the first primes with non-increasing exponents, which is exactly what the search enumerates (and it prunes branches already at least the best found).