Using prime factorization, any number can be represented as:

where are distinct prime factors and are their respective powers.

Number of Divisors

Formula:

Time Complexity:
Space Complexity:

long long countDivisors(long long n) {
    long long count = 1;
    
    for (long long d = 2; d * d <= n; d++) {
        if (n % d == 0) {
            int e = 0; 
            while (n % d == 0) {
                e++;
                n /= d;
            }
            count *= (e + 1);
        }
    }
    if (n > 1) {
        count *= (1 + 1); 
    }
    
    return count;
}

Algorithm:

  • Handle edge cases early by returning 0 if .
  • Initialize a running total count = 1.
  • Iterate through potential prime factors from up to (using instead of prevents integer overflow for very large numbers).
  • If divides , determine its frequency (exponent ) by repeatedly dividing by .
  • Multiply the running count by .
  • If after the loop completes, the remaining value is a prime factor itself (with an exponent of ); multiply the final count by (which is ).

Sum of Divisors

Formula:

Time Complexity:
Space Complexity:

long long divisorFunctions(long long n, bool wantSum) {
    long long count = 1;
    long long sum = 1;
    
    for (long long d = 2; d * d <= n; d++) {
        if (n % d == 0) {
            int e = 0;
            long long p_pow = d;
            while (n % d == 0) {
                e++;
                p_pow *= d;
                n /= d;
            }
            count *= (e + 1);
            sum *= (p_pow - 1) / (d - 1);
        }
    }
    if (n > 1) {
        count *= (1 + 1);
        sum *= (n * n - 1) / (n - 1); // equivalent to (n + 1)
    }
    
    return wantSum ? sum : count;
}
 

Algorithm:

  • Find the prime factorization of using Trial Division.
  • For each prime factor , count its frequency (exponent ).
  • Maintain running totals for count and sum by multiplying the respective formula terms at each prime step.

Euler’s Totient Function

Counts the number of positive integers up to that are relatively prime (coprime) to .
Formula:


*(Where iterates over all distinct prime factors of )

Time Complexity:
Space Complexity:

int phi(int n) {
    int result = n;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            while (n % i == 0) n /= i;
            result -= result / i; // equivalent to result = result * (1 - 1/i)
        }
    }
    if (n > 1) {
        result -= result / n;
    }
    return result;
}
 

Algorithm:

  • Initialize result = n.
  • Iterate through possible prime factors from to .
  • If divides , it is a prime factor. Remove all occurrences of from to avoid counting the same factor twice.
  • Multiply the result by (handled programmatically as result -= result / i).
  • If after the loop, the remaining is a prime factor itself; apply the formula one last time for .

GCD & LCM

The Euclidean algorithm is the standard way to find the largest number that divides two numbers.
Formula for LCM:

Time Complexity:
Space Complexity: (due to recursion stack)

long long gcd(long long a, long long b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}
 
long long lcm(long long a, long long b) {
    return (a / gcd(a, b)) * b; 
}

Algorithm:

  • Base case: If is , the GCD is .
  • Otherwise, recursively call the function replacing with , and with the remainder of divided by ().

Primality Test

Standard trial division test to check if a single number is prime.

  • Time Complexity:
  • Space Complexity:
bool isPrime(int n) {
    if(n <= 1) return false;
    if(n <= 3) return true;
    if(n % 2 == 0 || n % 3 == 0) return false;
    for(int i = 5; i * i <= n; i += 6) {
        if(n % i == 0 || n % (i + 2) == 0) return false;
    }
    return true;
}

Algorithm

  • Handle small cases (≤ 3) directly.
  • Check divisibility by 2 and 3.
  • Then test all possible divisors from 5 up to √n, stepping by 6 (covers numbers of the form 6k±1).
  • If any divisor divides n, it’s composite; otherwise it’s prime.

Linear Sieve

Computes the Smallest Prime Factor (SPF) and finds primes strictly in linear time.

  • Time Complexity:
  • Space Complexity:
vector<int> linearSieve(int n) {
    vector<int> lp(n + 1, 0), primes;
    for(int i = 2; i <= n; i++) {
        if(lp[i] == 0) { lp[i] = i; primes.push_back(i); }
        for(int p : primes) {
            if(p > lp[i] || 1LL * i * p > n) break;
            lp[i * p] = p;
        }
    }
    return primes;
}

Algorithm

  • Maintain an array lp that stores the smallest prime factor for each number.
  • Iterate i from 2 to n. If lp[i] is 0, i is prime – store its SPF and add it to the prime list.
  • For each prime p already found, assign p as the SPF of i*p, stopping when p exceeds lp[i] or i*p exceeds n.
  • This ensures every composite is generated exactly once.

Sieve of Eratosthenes

Generates all prime numbers up to a given limit .

  • Time Complexity:
  • Space Complexity:
vector<int> sieve(int n) {
    vector<bool> isPrime(n + 1, true);
    vector<int> primes;
    isPrime[0] = isPrime[1] = false;
    for(int i = 2; i <= n; i++) {
        if(isPrime[i]) {
            primes.push_back(i);
            for(long long j = 1LL * i * i; j <= n; j += i)
                isPrime[j] = false;
        }
    }
    return primes;
}

Algorithm

  • Start with all numbers from 2 to n marked as prime.
  • For each i that is still marked prime, add it to the list and mark all its multiples (starting from i*i) as non‑prime.
  • Return the list of primes.

Segmented Sieve

Finds all prime numbers in a specific range . Highly useful when is large but the difference is small enough to fit in memory.

  • Time Complexity:
  • Space Complexity:
vector<int> segmentedSieve(long long L, long long R) {
    long long lim = sqrt(R);
    vector<int> base = sieve(lim);
    vector<bool> isPrime(R - L + 1, true);
    for(long long p : base) {
        long long start = max(p * p, (L + p - 1) / p * p);
        for(long long j = start; j <= R; j += p)
            isPrime[j - L] = false;
    }
    vector<int> primes;
    for(long long i = 0; i <= R - L; i++)
        if(isPrime[i] && L + i >= 2) primes.push_back(L + i);
    return primes;
}

Algorithm

  • Generate all primes up to √R (these will be used to cross out composites).
  • Create a boolean array for the range [L, R] and initialise all as prime.
  • For each base prime p, find its first multiple within [L, R] and mark every multiple of p in that range as non‑prime.
  • Scan the range and collect the numbers still marked prime.

Prime Factorization using SPF

Uses precomputed Smallest Prime Factors (SPF) to answer prime factorization queries almost instantly.

  • Build Time:
  • Query Time: per factorization
  • Space Complexity:
vector<int> spf;
 
void buildSPF(int n) {
    spf.resize(n + 1);
    for(int i = 0; i <= n; i++) spf[i] = i;
    for(int i = 2; i * i <= n; i++) {
        if(spf[i] == i) {
            for(int j = i * i; j <= n; j += i)
                if(spf[j] == j) spf[j] = i;
        }
    }
}
 
vector<pair<int,int>> factorize(int x) {
    vector<pair<int,int>> res;
    while(x > 1) {
        int p = spf[x], cnt = 0;
        while(x % p == 0) { x /= p; cnt++; }
        res.push_back({p, cnt});
    }
    return res;
}

Algorithm

  • Build: Initialize spf[i] = i. For each prime i, iterate over its multiples starting from i*i and set spf[j] = i if it hasn’t been set yet.
  • Factorize: Repeatedly extract the smallest prime factor spf[x], count how many times it divides x, divide it out, and record the pair (prime, exponent).