Home/Learn/Sieve Variants & Multiplicative Functions

Pattern Guide

Sieve Variants & Multiplicative Functions

"Linear sieve, Euler's totient sieve, Möbius function. Each number factored once."

Beyond the basic Sieve of Eratosthenes: (1) Linear sieve factors each composite exactly once using smallest prime factors — O(n) and gives smallest prime factors for fast factorization. (2) Multiplicative function sieves compute Euler's totient φ(n), Möbius function μ(n), and divisor counts simultaneously. (3) Segmented sieve for ranges [L,R] with large L. Essential for number theory in competitive programming.

Problems you can solve with this pattern

4 problems · click any to start solving

All math →
1Count PrimesMediumSolve
2Smallest Value After Replacing With Sum of Prime FactorsMediumSolve
3Sum of All Subset XOR TotalsEasySolve
4Almost PrimeMediumSolve
Linear sieve with multiplicative functions
// Linear sieve: O(n), computes spf[], primes[], phi[], mu[]
function linearSieve(n) {
    const spf = new Array(n + 1).fill(0); // smallest prime factor
    const primes = [];
    const phi = new Array(n + 1).fill(0); // Euler's totient
    const mu = new Array(n + 1).fill(0);  // Möbius function
    phi[1] = 1; mu[1] = 1;

    for (let i = 2; i <= n; i++) {
        if (!spf[i]) { // i is prime
            spf[i] = i;
            primes.push(i);
            phi[i] = i - 1;
            mu[i] = -1;
        }
        for (const p of primes) {
            if (p > spf[i] || i * p > n) break;
            spf[i * p] = p;
            if (i % p === 0) {
                phi[i * p] = phi[i] * p; // p | i, so p^2 | ip
                mu[i * p] = 0;           // p^2 divides i*p
            } else {
                phi[i * p] = phi[i] * (p - 1); // gcd(i,p)=1
                mu[i * p] = -mu[i];
            }
        }
    }
    return { spf, primes, phi, mu };
}

// Factorize n using spf in O(log n)
function factorize(n, spf) {
    const factors = {};
    while (n > 1) {
        const p = spf[n];
        factors[p] = (factors[p] || 0) + 1;
        n /= p;
    }
    return factors;
}

// Segmented sieve for primes in [L, R]
function segmentedSieve(L, R) {
    const limit = Math.ceil(Math.sqrt(R));
    const smallPrimes = linearSieve(limit).primes;
    const sieve = new Array(R - L + 1).fill(true);
    if (L === 1) sieve[0] = false; // 1 is not prime
    for (const p of smallPrimes) {
        let start = Math.ceil(L / p) * p;
        if (start === p) start += p; // don't mark p itself
        for (let i = start; i <= R; i += p) sieve[i - L] = false;
    }
    return sieve.map((isPrime, i) => isPrime ? L + i : 0).filter(Boolean);
}

The linear sieve (smallest prime factor sieve) stores spf[n] = smallest prime factor of n. To factor any n: repeatedly divide by spf[n] until 1. O(log n) factorization after O(n) preprocessing. Euler's totient: φ(p) = p-1, φ(p^k) = p^(k-1)(p-1), φ(mn) = φ(m)φ(n) if gcd(m,n)=1. Möbius: μ(n) = 0 if p² | n, else (-1)^(number of prime factors).

Linear sieve with multiplicative functions
// Linear sieve: O(n), computes spf[], primes[], phi[], mu[]
function linearSieve(n) {
    const spf = new Array(n + 1).fill(0); // smallest prime factor
    const primes = [];
    const phi = new Array(n + 1).fill(0); // Euler's totient
    const mu = new Array(n + 1).fill(0);  // Möbius function
    phi[1] = 1; mu[1] = 1;

    for (let i = 2; i <= n; i++) {
        if (!spf[i]) { // i is prime
            spf[i] = i;
            primes.push(i);
            phi[i] = i - 1;
            mu[i] = -1;
        }
        for (const p of primes) {
            if (p > spf[i] || i * p > n) break;
            spf[i * p] = p;
            if (i % p === 0) {
                phi[i * p] = phi[i] * p; // p | i, so p^2 | ip
                mu[i * p] = 0;           // p^2 divides i*p
            } else {
                phi[i * p] = phi[i] * (p - 1); // gcd(i,p)=1
                mu[i * p] = -mu[i];
            }
        }
    }
    return { spf, primes, phi, mu };
}

// Factorize n using spf in O(log n)
function factorize(n, spf) {
    const factors = {};
    while (n > 1) {
        const p = spf[n];
        factors[p] = (factors[p] || 0) + 1;
        n /= p;
    }
    return factors;
}

// Segmented sieve for primes in [L, R]
function segmentedSieve(L, R) {
    const limit = Math.ceil(Math.sqrt(R));
    const smallPrimes = linearSieve(limit).primes;
    const sieve = new Array(R - L + 1).fill(true);
    if (L === 1) sieve[0] = false; // 1 is not prime
    for (const p of smallPrimes) {
        let start = Math.ceil(L / p) * p;
        if (start === p) start += p; // don't mark p itself
        for (let i = start; i <= R; i += p) sieve[i - L] = false;
    }
    return sieve.map((isPrime, i) => isPrime ? L + i : 0).filter(Boolean);
}
Linear sieve advantages over Eratosthenes:
- Exactly O(n) operations (vs O(n log log n))
- Computes SPF for O(log n) factorization
- Easily extended to compute φ(n), μ(n), Ω(n), σ(n) simultaneously

Multiplicative function sieve pattern: If f is multiplicative (f(mn)=f(m)f(n) when gcd(m,n)=1), compute during the linear sieve:
- f(p) = f at prime (base case)
- f(p^k) = formula for prime powers
- f(i*p) = f(i) * f(p) if gcd(i,p)=1, else special prime power formula

Möbius function use: Möbius inversion converts sum over divisors to sum over multiples. Core for "counting integers coprime to n" and inclusion-exclusion on divisors.