This article introduces Dirichlet convolution and Dirichlet generating functions.
Dirichlet convolution
For arithmetic functions and , their Dirichlet convolution (Dirichlet convolution), denoted by , is the arithmetic function
Dirichlet convolution is an important operation on arithmetic functions. Many properties of arithmetic functions can be uncovered through this operation.
Examples
-
The identity function is the Dirichlet convolution of the Möbius function and the constant function :
-
The divisor-counting function is the Dirichlet convolution of the constant function with itself:
-
The divisor-sum function is the Dirichlet convolution of the identity function and the constant function :
-
Euler's totient function is the Dirichlet convolution of the identity function and the Möbius function :
Möbius inversion uses to transform identities of arithmetic functions.
Properties
Dirichlet convolution has a series of algebraic properties.
Theorem
Let be arithmetic functions. Then:
-
Commutativity: .
-
Associativity: .
-
Distributivity: .
-
Identity element: , where is the identity element for convolution, and is the Iverson bracket.
-
Inverse: If and only if , there exists such that . The function is called the Dirichlet inverse of and can be denoted by . Moreover, the inverse satisfies the recurrence
Proof
To verify commutativity, direct computation gives
To verify associativity, direct computation gives
To verify distributivity, direct computation gives
To verify that is the identity element, direct computation gives
The second equality holds because is nonzero only when , that is, when .
Finally, we need to prove that exists if and only if . For any , suppose that there is a such that . This means that
This gives a system of equations for the values , from which can be determined directly. In particular, when , the equation becomes , so the existence of requires at least . Conversely, whenever , we can solve directly for
This can be used to compute the values of recursively. Therefore, the inverse exists if and only if .
In the language of abstract algebra, these algebraic properties mean that all arithmetic functions form a commutative ring under pointwise addition and Dirichlet convolution, and its units are precisely the functions that are nonzero at . This ring is called the Dirichlet ring (Dirichlet ring).
Multiplicative functions are a special class of arithmetic functions. They are closed under Dirichlet convolution and Dirichlet inversion.
Theorem
Let be multiplicative functions. Then is also multiplicative. Moreover, the inverse always exists and is also multiplicative.
Proof
For the first claim, let . Direct verification shows that, for ,
The logic behind changing the order of summation in the third equality is as follows: when ranges over the divisors of , 's prime factors can be divided into two groups according to whether they are prime factors of or . Multiplying the prime factors, with multiplicity, in the two groups separately gives and , which range over the divisors of and , respectively. Conversely, given divisors and of and , we can always obtain the divisor of . For the second claim, let and apply mathematical induction. First, . The recurrence for the inverse can then be written as
Thus, for with , we have
The second equality uses the induction hypothesis: for with , the condition holds.
In the language of abstract algebra, all multiplicative functions form a subgroup of the multiplicative group of the Dirichlet ring.
An even more special class is that of completely multiplicative functions.
Theorem
Let be a completely multiplicative function, and let be arithmetic functions. Then:
- Distributivity: .
- Inverse: , provided that exists.
- A multiplicative function is completely multiplicative if and only if , where is the Möbius function.
Proof
For the first statement, direct verification gives
The third equality uses the property of completely multiplicative functions that for every .
For the second statement, the first statement gives
Here, the last equality uses only . By the definition of the inverse, .
For the third statement, using the second statement and , if is completely multiplicative, then
Here, is the constant function. Conversely, if is multiplicative and , it is enough to prove that for every prime and in order to prove that is completely multiplicative. To this end, apply mathematical induction on . The statement is obvious at the base case . For any , the inverse recurrence gives
The last equality uses the induction hypothesis . Applying gives
Substituting into the previous equation gives
Thus, the induction step holds, and the original statement follows.
In the language of abstract algebra, if is completely multiplicative, the map is an endomorphism of the Dirichlet ring.
Dirichlet generating functions
Closely related to Dirichlet convolution are Dirichlet generating functions.
The Dirichlet generating function (Dirichlet series generating function, DGF) corresponding to an arithmetic function —that is, the sequence —is defined as the formal Dirichlet series (formal Dirichlet series):
The in the series is a formal variable. In common Dirichlet generating functions, can often be regarded as a complex variable, allowing one to study the analytic properties of Dirichlet series, but this lies beyond the scope of algorithmic competitions.
The product of Dirichlet generating functions corresponds to the Dirichlet convolution of the associated arithmetic functions:
Theorem
For arithmetic functions and their Dirichlet generating functions , the generating function of their Dirichlet convolution is .
Proof
Direct verification:
Using the correspondence between Dirichlet convolution and products of Dirichlet generating functions, we can understand the properties of Dirichlet convolution from the perspective of Dirichlet generating functions. Since multiplication of formal Dirichlet series satisfies commutativity, associativity, and distributivity over addition, Dirichlet convolution of arithmetic functions satisfies the same algebraic properties.
Euler products
The special nature of multiplicative functions is also reflected in Dirichlet generating functions. Since integers have the unique factorization theorem, the generating function of a multiplicative function can be written as follows:
This means that can be decomposed into a product of several , where the arithmetic function corresponding to each can be nonzero only at powers of . This infinite product is also called an Euler product (Euler product). If both and can be decomposed in this form, then so can their product; translated back to arithmetic functions, this observation says that the Dirichlet convolution of multiplicative functions is still multiplicative.
Furthermore, if is also completely multiplicative, then , and the above expression can be simplified further:
Unlike multiplicative functions, the forms of Dirichlet generating functions of completely multiplicative functions are not closed under multiplication. Therefore, the Dirichlet convolution and Dirichlet inverse of completely multiplicative functions need not be completely multiplicative, although they are always multiplicative.
Examples
-
The identity function is completely multiplicative. Its Dirichlet generating function is the constant function of the formal variable
-
The constant function is completely multiplicative. Its Dirichlet generating function is the Riemann zeta function
-
The Möbius function is the Dirichlet inverse of the constant function. Its Dirichlet generating function is the reciprocal of :
-
The power function is completely multiplicative. In particular, when , it is the constant function; when , it is the identity function. Its Dirichlet generating function is
-
Euler's totient function is multiplicative. Its Dirichlet generating function is
Combining this with the Dirichlet expression for the power function gives .
-
The divisor function is multiplicative. Its Dirichlet generating function is
Combining this with the Dirichlet expression for the power function gives . This is exactly the defining formula for .
-
The indicator function of square-free numbers is multiplicative. Its Dirichlet generating function is
Applications
Dirichlet generating functions can be used to express multiplicative functions as Dirichlet convolutions.
For example, in the process of the Du Jiao sieve, to compute the prefix sum of a multiplicative function , we need to find another multiplicative function such that both and have prefix sums that can be computed quickly. This process can be derived using Dirichlet generating functions.
Taking the example Luogu P3768 Simple Mathematical Problem from the Du Jiao sieve section, we need to construct an arithmetic function satisfying the conditions above for . Since is multiplicative, its Dirichlet generating function is
Comparing this with the Dirichlet generating function of the power function, we see that taking gives . Both prefix sums can be computed quickly.
Computing Dirichlet convolution
This section discusses computing Dirichlet convolution: given the sequences and , find the first several terms of the Dirichlet convolution . The complexity of the algorithm varies slightly depending on the properties of the functions involved.
General case
If have no special properties, Dirichlet convolution can only be computed from its definition:
Enumerate and , and add the contribution to . The enumeration complexity is
The reference implementation is as follows:
Reference Implementation
// Compute the Dirichlet convolution h = f * g.
auto dirichlet_convolute(const std::vector<int>& f, const std::vector<int>& g) {
int n = f.size() - 1;
std::vector<int> h(n + 1);
for (int k = 1; k <= n; ++k) {
for (int d = 1; k * d <= n; ++d) {
h[k * d] += f[k] * g[d];
}
}
return h;
}
Case of convolution with a multiplicative function
If is multiplicative, the computation of Dirichlet convolution can be accelerated using the Euler product. Computing is equivalent to computing the coefficients of its Dirichlet generating function . Since
Here, is a factor in the Euler product decomposition of ; it contains only the coefficients at powers of :
Starting with , we can traverse every prime not exceeding and multiply by one by one to obtain the final result . When multiplying by , we can directly apply the brute-force enumeration algorithm from the general case. The total number of enumerations is
The complexity estimate in the last step is the same as the proof of the complexity of the Sieve of Eratosthenes. Therefore, the time complexity of this algorithm is .
The reference implementation is as follows:
Reference Implementation
// Compute the Dirichlet convolution h = f * g.
// Assume that g is multiplicative.
auto dirichlet_convolute(const std::vector<int>& f, const std::vector<int>& g) {
int n = f.size() - 1;
std::vector<int> h(f);
std::vector<bool> vis(n + 1);
for (int i = 2; i <= n; ++i) {
if (vis[i]) continue;
// Reverse the order for in-place computation.
for (int k = n / i * i; k; k -= i) {
vis[k] = true;
int d = k;
while (true) {
d /= i;
h[k] += h[d] * g[k / d];
if (d % i) break;
}
}
}
return h;
}
In particular, when the multiplicative function is completely multiplicative or is a Dirichlet inverse, such as when or , the algorithm can be simplified further. In this case, the Dirichlet convolution can be computed using the Dirichlet prefix-sum/difference algorithm with a smaller constant, but the time complexity remains .
Case where the result is multiplicative
Finally, consider the case where is multiplicative. In particular, when both are multiplicative, is multiplicative. To compute , it is enough to determine its values at prime powers, after which it can be computed in time using the linear sieve. For a prime power , the value can be computed by brute force directly:
The number of iterations required for these brute-force computations is
Therefore, the total time complexity of this algorithm is .
The reference implementation is as follows:
Reference Implementation
// Compute the Dirichlet convolution h = f * g.
// Assume that h is multiplicative.
auto dirichlet_convolute(const std::vector<int>& f, const std::vector<int>& g) {
int n = f.size() - 1;
std::vector<int> h(n + 1), primes, rem(n + 1), lpf(n + 1);
std::vector<bool> vis(n + 1);
h[1] = 1;
for (int x = 2; x <= n; ++x) {
if (!vis[x]) {
primes.push_back(x);
rem[x] = 1;
lpf[x] = x;
}
for (int p : primes) {
if (x * p > n) break;
vis[x * p] = true;
rem[x * p] = x % p ? x : rem[x];
lpf[x * p] = p;
if (x % p == 0) break;
}
if (rem[x] == 1) { // prime powers.
for (int k = x; k; k /= lpf[x]) {
h[x] += f[k] * g[x / k];
}
} else { // other cases.
h[x] = h[rem[x]] * h[x / rem[x]];
}
}
return h;
}