Möbius inversion is an important technique in number theory used to recover an arithmetic function when its divisor-sum function is known. It is based on the Möbius function, denoted by μ(n).
The basic idea is:
If a function g(n) is defined as the sum of another function f(d) over all divisors d of n, then Möbius inversion allows us to recover f(n) from g(n).
Möbius Function:
The Möbius function μ(n) is defined for every positive integer n as follows:
- μ(1) = 1
- μ(n) = 0 if n is divisible by the square of a prime number.
- μ(n) = 1 if n is square-free and has an even number of distinct prime factors.
- μ(n) = -1 if n is square-free and has an odd number of distinct prime factors.
A number is called square-free if it is not divisible by the square of any prime number.
Möbius Inversion Formula:
Suppose two arithmetic functions f(n) and g(n) satisfy: g(n) = Σ f(d), where d divides n. In other words, g(n) is the sum of f(d) over all positive divisors d of n.
Then f(n) can be recovered using the Möbius inversion formula: f(n) = Σ μ(d) × g(n / d), where d divides n
Equivalently, the formula can also be written as: f(n) = Σ μ(n / d) × g(d), where d divides n. Both forms are equivalent because if d divides n, then n / d is also a divisor of n.
Why Does Möbius Inversion Work?
The key property of the Möbius function is:
- The sum of μ(d) over all divisors d of n is 1 when n = 1.
- The sum is 0 when n > 1.
where the summation is taken over all divisors d of n.
- In compact form: Σ μ(d) = [n = 1]
- Now, assume: g(n) = Σ f(d)
- Taking the divisor sum: Σ μ(d) × g(n / d)
- Substituting the definition of g: Σ μ(d) × Σ f(e)
- After rearranging the divisor sums, the Möbius function cancels all terms except the term corresponding to f(n). Therefore: f(n) = Σ μ(d) × g(n / d)
This is the fundamental idea behind Möbius inversion.
Let us Understand Möbius Inversion with an Example:
Suppose: f(n) = n and define: g(n) = Σ d, where the summation is over all divisors d of n. Thus, g(n) is the sum of all divisors of n.
For example, consider n = 6, The divisors of 6 are: 1, 2, 3, 6
Therefore:
- g(1) = 1
- g(2) = 1 + 2 = 3
- g(3) = 1 + 3 = 4
- g(6) = 1 + 2 + 3 + 6 = 12
Now, using Möbius inversion: f(6) = Σ μ(d) × g(6 / d), The divisors of 6 are 1, 2, 3, and 6. So: f(6) = μ(1)g(6) + μ(2)g(3) + μ(3)g(2) + μ(6)g(1)
Using:
- μ(1) = 1
- μ(2) = -1
- μ(3) = -1
- μ(6) = 1
We get: f(6) = 1 × 12 - 1 × 4 - 1 × 3 + 1 × 1, f(6) = 12 - 4 - 3 + 1 = 6. Thus, we successfully recover: f(6) = 6
Precompute Möbius Function Using Sieve - O(n log n) Time and O(n) Space
The idea is to first precompute the values of the Möbius function using a sieve-based approach.
Initially:
- Set μ(1) = 1.
- Assume every number has a Möbius value of 1.
- For every prime number p, multiply the Möbius value of its multiples by -1.
- If a number is divisible by p², its Möbius value becomes 0.
After precomputing μ(n), we can apply the Möbius inversion formula directly.
Working of Approach:
- First, precompute the Möbius function values for all numbers from 1 to N using a sieve-based approach.
- Compute g(n) as the sum of all divisors of every number up to N.
- For the given value n, iterate through all its divisors d.
- For every divisor, add μ(d) × g(n / d) to the result.
- According to the Möbius inversion formula, the final result recovers the original value f(n).
Let us understand with an example:
Input: n = 6
The divisors of 6 are 1, 2, 3, 6.
Compute Möbius values
The required Möbius values are:
- μ(1) = 1
- μ(2) = -1
- μ(3) = -1
- μ(6) = 1
Compute divisor-sum values
Since g(n) is the sum of all divisors of n:
- g(1) = 1
- g(2) = 1 + 2 = 3
- g(3) = 1 + 3 = 4
- g(6) = 1 + 2 + 3 + 6 = 12
Apply Möbius Inversion
- Using: f(n) = Σ μ(d) × g(n / d)
- For n = 6: f(6) = μ(1) × g(6) + μ(2) × g(3) + μ(3) × g(2) + μ(6) × g(1) = 1 × 12 - 1 × 4 - 1 × 3 + 1 × 1 = 12 - 4 - 3 + 1 = 6
- Thus, the final result is: f(6) = 6.
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int mobius[N + 1];
bool isPrime[N + 1];
// Precompute Mobius function values up to N
void precomputeMobius()
{
// Initialize Mobius values and prime markers
for (int i = 0; i <= N; i++)
{
mobius[i] = 1;
isPrime[i] = true;
}
isPrime[0] = false;
isPrime[1] = false;
// Process every prime number
for (int p = 2; p <= N; p++)
{
if (isPrime[p])
{
// Mark multiples of p as non-prime
for (int multiple = p * 2; multiple <= N; multiple += p)
{
isPrime[multiple] = false;
}
// Flip the sign for every prime factor
for (int j = p; j <= N; j += p)
{
mobius[j] *= -1;
}
// Numbers divisible by p squared have value 0
for (int j = p * p; j <= N; j += p * p)
{
mobius[j] = 0;
}
}
}
}
// Recover f(n) using the Mobius inversion formula
int mobiusInversion(int n)
{
precomputeMobius();
// Compute g(n) as the sum of all divisors of n
int g[N + 1] = {};
for (int d = 1; d <= N; d++)
{
for (int multiple = d; multiple <= N; multiple += d)
{
g[multiple] += d;
}
}
int res = 0;
// Apply Mobius inversion over all divisors of n
for (int d = 1; d <= n; d++)
{
if (n % d == 0)
{
res += mobius[d] * g[n / d];
}
}
return res;
}
int main()
{
int n = 6;
cout << "f(" << n << ") = " << mobiusInversion(n) << endl;
return 0;
}
import java.util.*;
public class GFG {
static final int N = 10;
static int[] mobius = new int[N + 1];
static boolean[] isPrime = new boolean[N + 1];
// Precompute Mobius function values up to N
static void precomputeMobius()
{
// Initialize Mobius values and prime markers
for (int i = 0; i <= N; i++) {
mobius[i] = 1;
isPrime[i] = true;
}
isPrime[0] = false;
isPrime[1] = false;
// Process every prime number
for (int p = 2; p <= N; p++) {
if (isPrime[p]) {
// Mark multiples of p as non-prime
for (int multiple = p * 2; multiple <= N;
multiple += p) {
isPrime[multiple] = false;
}
// Flip the sign for every prime factor
for (int j = p; j <= N; j += p) {
mobius[j] *= -1;
}
// Numbers divisible by p squared have value
// 0
for (int j = p * p; j <= N; j += p * p) {
mobius[j] = 0;
}
}
}
}
// Recover f(n) using the Mobius inversion formula
static int mobiusInversion(int n)
{
precomputeMobius();
// Compute g(n) as the sum of all divisors of n
int[] g = new int[N + 1];
for (int d = 1; d <= N; d++) {
for (int multiple = d; multiple <= N;
multiple += d) {
g[multiple] += d;
}
}
int res = 0;
// Apply Mobius inversion over all divisors of n
for (int d = 1; d <= n; d++) {
if (n % d == 0) {
res += mobius[d] * g[n / d];
}
}
return res;
}
public static void main(String[] args)
{
int n = 6;
System.out.println("f(" + n
+ ") = " + mobiusInversion(n));
}
}
N = 10
mobius = [1] * (N + 1)
isPrime = [True] * (N + 1)
# Precompute Mobius function values up to N
def precomputeMobius():
# Initialize Mobius values and prime markers
isPrime[0] = False
isPrime[1] = False
# Process every prime number
for p in range(2, N + 1):
if isPrime[p]:
# Mark multiples of p as non-prime
for multiple in range(p * 2, N + 1, p):
isPrime[multiple] = False
# Flip the sign for every prime factor
for j in range(p, N + 1, p):
mobius[j] *= -1
# Numbers divisible by p squared have value 0
for j in range(p * p, N + 1, p * p):
mobius[j] = 0
# Recover f(n) using the Mobius inversion formula
def mobiusInversion(n):
precomputeMobius()
# Compute g(n) as the sum of all divisors of n
g = [0] * (N + 1)
for d in range(1, N + 1):
for multiple in range(d, N + 1, d):
g[multiple] += d
res = 0
# Apply Mobius inversion over all divisors of n
for d in range(1, n + 1):
if n % d == 0:
res += mobius[d] * g[n // d]
return res
if __name__ == "__main__":
n = 6
print(f"f({n}) = {mobiusInversion(n)}")
using System;
public class GFG {
const int N = 10;
static int[] mobius = new int[N + 1];
static bool[] isPrime = new bool[N + 1];
// Precompute Mobius function values up to N
static void precomputeMobius()
{
// Initialize Mobius values and prime markers
for (int i = 0; i <= N; i++) {
mobius[i] = 1;
isPrime[i] = true;
}
isPrime[0] = false;
isPrime[1] = false;
// Process every prime number
for (int p = 2; p <= N; p++) {
if (isPrime[p]) {
// Mark multiples of p as non-prime
for (int multiple = p * 2; multiple <= N;
multiple += p) {
isPrime[multiple] = false;
}
// Flip the sign for every prime factor
for (int j = p; j <= N; j += p) {
mobius[j] *= -1;
}
// Numbers divisible by p squared have value
// 0
for (int j = p * p; j <= N; j += p * p) {
mobius[j] = 0;
}
}
}
}
// Recover f(n) using the Mobius inversion formula
static int mobiusInversion(int n)
{
precomputeMobius();
// Compute g(n) as the sum of all divisors of n
int[] g = new int[N + 1];
for (int d = 1; d <= N; d++) {
for (int multiple = d; multiple <= N;
multiple += d) {
g[multiple] += d;
}
}
int res = 0;
// Apply Mobius inversion over all divisors of n
for (int d = 1; d <= n; d++) {
if (n % d == 0) {
res += mobius[d] * g[n / d];
}
}
return res;
}
public static void Main()
{
int n = 6;
Console.WriteLine("f(" + n
+ ") = " + mobiusInversion(n));
}
}
const N = 10;
let mobius = Array(N + 1).fill(1);
let isPrime = Array(N + 1).fill(true);
// Precompute Mobius function values up to N
function precomputeMobius()
{
// Initialize Mobius values and prime markers
isPrime[0] = false;
isPrime[1] = false;
// Process every prime number
for (let p = 2; p <= N; p++) {
if (isPrime[p]) {
// Mark multiples of p as non-prime
for (let multiple = p * 2; multiple <= N;
multiple += p) {
isPrime[multiple] = false;
}
// Flip the sign for every prime factor
for (let j = p; j <= N; j += p) {
mobius[j] *= -1;
}
// Numbers divisible by p squared have value 0
for (let j = p * p; j <= N; j += p * p) {
mobius[j] = 0;
}
}
}
}
// Recover f(n) using the Mobius inversion formula
function mobiusInversion(n)
{
precomputeMobius();
// Compute g(n) as the sum of all divisors of n
let g = Array(N + 1).fill(0);
for (let d = 1; d <= N; d++) {
for (let multiple = d; multiple <= N;
multiple += d) {
g[multiple] += d;
}
}
let res = 0;
// Apply Mobius inversion over all divisors of n
for (let d = 1; d <= n; d++) {
if (n % d === 0) {
res += mobius[d] * g[Math.floor(n / d)];
}
}
return res;
}
// Driver Code
const n = 6;
console.log(`f(${n}) = ${mobiusInversion(n)}`);
Output
f(6) = 6
Note: The value of N is set to 10 for demonstration purposes. For larger values of n, increase N accordingly.
Applications of Möbius Inversion:
Möbius inversion is commonly used in number theory and competitive programming for:
- Recovering a function from its divisor sums.
- Counting coprime pairs.
- Inclusion-exclusion problems involving divisibility.
- Computing arithmetic functions.
- Problems involving the greatest common divisor.
- Counting objects with exact divisibility properties.