Dirichlet 卷积

狄克卷积

狄利克雷卷积

对于积性函数 \(f(x)\)\(g(x)\),定义 \(h = f * g\),那么:

\[h(n) = (f * g)(n) = \sum_{d \mid n} f(d) g(\frac n d) \]

积性函数定义

若对于 \(\forall a, b\)\(\gcd(a, b) = 1\),有 \(f(ab) = f(a) f(b)\),那么 \(f(x)\) 为积性函数。

性质

  1. \(f\)\(g\) 皆为积性则 \(f * g\) 也为积性。

  2. 所有积性函数都可以利用线性筛筛出值。

数论函数

注意数论函数全是积性函数,本文也只讨论积性函数。

单位根函数 \(\epsilon(x)\)

\[\epsilon(x) = \begin{cases} 1 \quad (x = 1) \\ 0 \quad (x \ne 1) \end{cases} \]

显然 \(\forall f, f * \epsilon = \epsilon * f = f\)

幂函数 \(Id_k(x)\)

\(Id_k(x) = x^k\)。特别的,\(Id_1(x) = x\)\(Id_0(x) = 1\)\(Id_0(x)\) 被称为常函数,简记为 \(I\)

\(I(x)\)

对于 \(\forall f\),有:

\[(f * I)(n) = \sum_{d \mid n} f(d) I(n / d) = \sum \]

欧拉函数 \(\varphi(x)\)

\(\varphi(x)\) 是小于等于 \(x\) 的正整数中与 \(x\) 互质的数的个数。

\[\varphi(n) = n \prod_{p|n} \left(1 - \frac{1}{p}\right) \\ = \prod (p - 1) p ^ {k - 1} \]

贝尔级数 / 狄利克雷生成函数

\(f(x)\),那么对于任意质数 \(p\) 其贝尔级数为 \(F_p (x)\),有:

\[F_p (x) = \sum_{k = 0}^{\infty} f(p^k) x^k \]

莫比乌斯反演

我们假设 \(I\) 的逆元为 \(\mu\),那么有:

\[I * \mu = \mu * I = \epsilon \]

那么我们现在来求 \(\mu\) 的值。设 \(F_p (x)\)\(I\) 的贝尔级数,显然:

\[F_p (x) = \sum_{k = 0} ^ {\infty} I(p^k) x ^ k \]

\[= \sum_{k = 0} ^ {\infty} x ^ k \]

\[= \frac{1}{1 - x} \]

根据 \(I * \mu = \epsilon\) 我们可以求出 \(\mu\) 的贝尔级数 \(G_p(x)\)

\[G_p(x) = \frac 1 {F_p(x)} = 1 - x \]

所以对于 \(\mu(x)\) 和任意质数 \(p\) 显然有:

\[\mu(p ^ 0) = 1 \quad \mu(p ^ 1) = -1 \quad \mu(p ^ k) = 0 \quad (k > 1) \]

那么利用积性函数的性质求出 \(\mu(x)\) 在每个位置的值为:

\[\mu(n) = \begin{cases} 1 \quad (n = 1) \\ (-1)^k \quad (n = p_1 p_2 ... p_k) \\ 0 \quad (n = p_1 ^ {k_1} p_2 ^ {k_2} ... p_m ^ {k_m}, \exists k_i > 1) \end{cases} \]

对于任意积性函数都可以使用贝尔级数求出其逆。

那么对于 \(f * I = g\),我们有:

\[g * \mu = f * I * \mu = f * \epsilon = f \]

这就是莫比乌斯反演。我们把它写成公式,对于 \(\forall f(x), g(x)\),若存在关系:

\[g(n) = \sum_{d \mid n} f(d) \]

那么有:

\[f(n) = \sum_{d \mid n} g(d) \mu(\frac n d) \]

可利用于容斥或是推式子。

数论函数递推关系式

假设 \(f \rightarrow g\) 的关系代表 \(f * I = g\)\(g * \mu = f\),那么有:

\[\mu \rightarrow \epsilon \rightarrow I \qquad \varphi \rightarrow Id_1 \]

杜教筛

对于 \(h(x) = \sum_{d \mid x} f(d) g(\frac n d)\),如果可以快速求出 \(\sum_{x = 1} ^ {\forall n} h(x)\)\(\sum_{x = 1} ^ {\forall n} g(x)\),那么就可以利用杜教筛在 \(O(n ^ \frac 2 3)\) 的时间复杂度内求出 \(\sum_{x = 1} ^ {\forall n} f(x)\)

我们列出等式:

\[\sum_{i = 1} ^ n h(i) = \sum_{i = 1} ^ n \sum_{d \mid i} f(d) g(\frac i d) \]

反一下:

\[\sum_{i = 1} ^ n h(i) = \sum_{i = 2} ^ n \sum_{d \mid i} g(d) f(\frac i d) + \sum_{i = 1} ^ n f(i) g(1) \]

\[= \sum_{d = 1} ^ n g(d) \sum_{i = 2} ^ {\lfloor \frac n d \rfloor} f(i) + g(1) \sum_{i = 1} ^ n f(i) \]

我们设 \(s(x) = \sum_{i = 1} ^ x f(i)\),那么我们要求的就是 \(s(n)\),带入得:

\[\sum_{i = 1} ^ n h(i) = \sum_{d = 2} ^ n g(d) s(\lfloor \frac n d \rfloor) + g(1) s(n) \]

移项,得:

\[s(n) = \frac{\sum_{i = 1} ^ n h(i) - \sum_{d = 2} ^ n g(d) s(\lfloor \frac n d \rfloor)}{g(1)} \]

数论分块并记忆化搜索即可。

洛谷模板的代码

洛谷模板 link


const int mod = 998244353, maxn = 5 * 1e6;

ll phi[maxn], mu[maxn];
unordered_map <ll, ll> sumphi, summu; 
vector <ll> prime;
bool vis[maxn];

void pre() {
    if(mu[1]) AC;
    phi[1] = mu[1] = 1;
    for(int i = 2; i < maxn; i++) {
        if(!vis[i]) {
            prime.push_back(i);
            vis[i] = true;
            phi[i] = i - 1;
            mu[i] = -1;
        }
        for(int p : prime) {
            if((ll) i * p >= maxn) break;
            if(i % p == 0) {
                vis[i * p] = true;
                mu[i * p] = 0;
                phi[i * p] = phi[i] * p;
                break;
            }
            vis[i * p] = true;
            mu[i * p] = -mu[i];
            phi[i * p] = phi[i] * (p - 1);
        }
        phi[i] += phi[i - 1];
        mu[i] += mu[i - 1];
    }
}

il ll sphi(ll n) {
    if(n < maxn) return phi[n];
    if(sumphi.count(n)) return sumphi[n];
    ll res = n * (n + 1) / 2;
    for(ll l = 2, r; l <= n; l = r + 1) {
        r = n / (n / l);
        res -= (r - l + 1) * sphi(n / l);
    }
    sumphi[n] = res;
    return res;
}

il ll smu(ll n) {
    if(n < maxn) return mu[n];
    if(summu.count(n)) return summu[n];
    ll res = 1;
    for(ll l = 2, r; l <= n; l = r + 1) {
        r = n / (n / l);
        res -= (r - l + 1) * smu(n / l);
    }
    summu[n] = res;
    return res;
}

ll n;

void ACehomoxue() {
	pre();
    cin >> n;
    cout << sphi(n) << ' ' << smu(n);
    el;
}
posted @ 2026-06-28 14:31  ACehomoxue  阅读(5)  评论(0)    收藏  举报