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).

FunctionDefinitionType
(identity of )completely multiplicative
completely multiplicative
completely multiplicative
multiplicative
if squarefree, else 0 if , if multiplicative
number of divisorsmultiplicative
multiplicative
, distinct prime factors / with multiplicity / additive
product of the distinct primesmultiplicative
aliquot sum (proper divisors)——

The Dirichlet algebra

IdentityMeaning
, 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)

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)6720103 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).

QuantityFormula
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;
}

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 .)

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;
    }
};

Patterns

ProblemApproach
count numbers with exactly divisorssieve ; or enumerate exponent signatures with
smallest number with at least divisors / highly composite numbersDFS 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 rootsorder 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;
}