莫比乌斯反演

莫比乌斯反演

莫比乌斯函数

\(\mu(d)\) 本质上是一个经过总结规律得出的容斥系数、定义如下:

  1. \(d=1\) 时, \(\mu(d)=1\)
  2. \(d=\prod_{i=1}^k p_i\) ,其中 \(p_i\) 为互异素数,则 \(\mu(d)=(-1)^k\) ,即质因数次数最大为 1
  3. 其他情况,\(\mu(d)=0\) ,即存在次数大于 1 的质因数

有如下性质:

  1. \(\sum_{d|n}\mu(d)=[n=1]\) ,证明如下:

    • \(n=1\) 时成立

    • \(n>1\) ,可分解为 \(n=\prod_{i=1}^k p_i^{a_i}\)\(n\) 的因子的 \(\mu\) 值不为 0 只有质因数次数都为 1 的因子

      显然由 \(r\) 个质因数构成的因子有 \(C_k^r\)

      \(\sum_{d|n}\mu(d)=\sum_{i=0}^k(-1)^k C_{k}^i\) ,即所有不为 0 的因子的贡献和

      由二项式定理:\((x+y)^k=\sum_{i=0}^k C_{k}^i x^i y^{n-i}\)

      \(\sum_{i=0}^k(-1)^k C_{k}^i=[(-1)+1]^k=0\)

  2. \(\sum_{d|n}\dfrac{\mu(d)}{d}=\dfrac{\varphi(n)}{n}\)

    用狄利克雷卷积可证

  3. 积性函数

积性函数自然可以线性筛

const int N = 1e7 + 5;
int vis[N], pr[N], cnt, mu[1];
void get() {
    mu[1] = 1;
    for (int i = 2; i <= 1e7; i++) {
        if (!vis[i]) pr[++cnt] = i;
        for (int j = 1, x; j <= cnt && i * pr[j] <= 1e7; j++) {
            vis[x = i * pr[j]] = 1;
            if (i % pr[j] == 0) { mu[x] = 0; break; }
            mu[x] = -mu[i];
        }
    }
}

莫比乌斯反演

公式

\[F(n)=\sum_{d|n}f(d)\Rightarrow f(n)=\sum_{d|n}\mu(d)F(\dfrac{n}{d}) \]

证明:

\[\begin{aligned} \sum_{d|n}\mu(d)F(\dfrac{n}{d}) &= \sum_{d|n}\mu(d)\sum_{k|\frac{n}{d}}f(k)\\ &= \sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d)\\ &= \sum_{k|n}f(k)[\frac{n}{k}=1]\\ &= f(n) \end{aligned} \]

这里还有第二个形式,在推导中更为常用

\[F(n)=\sum_{n|d}f(d)\Rightarrow f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d) \]

证明,另 \(t=\frac{d}{n}\)

\[\begin{aligned} \sum_{n|d}\mu(\frac{d}{n})F(d) &=\sum_{t=1}^{+\infin}\mu(t)F(nt)\\ &=\sum_{t=1}^{+\infin}\mu(t)\sum_{nt|k}f(k)\\ &=\sum_{n|k}f(k)\sum_{t|\frac{k}{n}}\mu(t)\\ &=\sum_{n|k}f(k)[\frac{k}{n}=1]\\ &=f(n) \end{aligned} \]

莫比乌斯反演公式的本质上都是 \(\sum_{d|n}\mu(d)=[n=1]\)

实际情况,推导时用莫反公式却麻烦,用这个性质更为简单

但是完整用公式推导可以更好地练习

[POI2007] Queries

\(\sum_{i=1}^a\sum_{j=1}^b[\gcd(i,j)=k]\)

sol 1

\(F(n)\) 为满足 \(n|\gcd(i,j)\)\((i,j)\) 对数,\(f(n)\) 为满足 \(n=\gcd(i,j)\)\((i,j)\) 对数,所求为 \(f(k)\)

由于 \(n|\gcd(i,j)\) ,则 \(i,j\) 都是 \(n\) 的倍数,组合数学知识得到 \(F(n)=\lfloor\dfrac{a}{n}\rfloor\lfloor\dfrac{b}{n}\rfloor\)

显然 \(F(n)=\sum_{n|d}f(d)\) ,这是莫反的第二种形式,反演得到

\[\begin{aligned} f(n)&=\sum_{n|d}\mu(\dfrac{d}{n})F(d)\\ &=\sum_{i=1}^{\min(\lfloor\frac{a}{n}\rfloor,\lfloor\frac{b}{n}\rfloor)}\mu(i)F(in)\\ &=\sum_{i=1}^{\min(\lfloor\frac{a}{n}\rfloor,\lfloor\frac{b}{n}\rfloor)}\mu(i) \lfloor\dfrac{a}{in}\rfloor\lfloor\dfrac{b}{in}\rfloor \end{aligned} \]

预处理 \(\mu\) 的前缀和,整除分块即可

sol 2

难以理解?考虑不用反演公式

显然 \(i,j\) 都要是 \(k\) 的倍数,枚举这个倍数,即可转换为互质问题

\(x=\lfloor\frac{a}{k}\rfloor,y=\lfloor\frac{b}{k}\rfloor\)

\[\begin{aligned} \sum_{i=1}^a\sum_{j=1}^b[\gcd(i,j)=k]&= \sum_{i=1}^{x}\sum_{j=1}^{y}[\gcd(i,j)=1] \end{aligned} \]

\(\sum_{d|n}\mu(d)=[n=1]\) 代入

\[\sum_{i=1}^{x}\sum_{j=1}^{y}\sum_{d|gcd(i,j)}\mu(d) \]

枚举 \(\gcd\)

\[\sum_{i=1}^{x}\sum_{j=1}^{y}\sum_{d=1}^{\min(x,y)} \mu(d)[d|i][d|j] \]

各回各家

\[\sum_{d=1}^{\min(x,y)}\mu(d)\sum_{i=1}^{x}[d|i]\sum_{j=1}^{y}[d|j] \]

后面两个 \(\sum\) 可以直接求?

\[\sum_{d=1}^{\min(x,y)}\mu(d)\lfloor\dfrac{x}{d}\rfloor\lfloor\dfrac{y}{d}\rfloor \]

整除分块即可

code

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
typedef long double LD;
typedef long long LL;
typedef double db;
const int N = 5e4 + 5;
int Ti, n, m, K, vis[N], pr[N], cnt, mu[N], res, s[N];
int main() {
    mu[1] = 1;
    for (int i = 2; i <= 5e4; i++) {
        if (!vis[i]) pr[++cnt] = i, mu[i] = -1;
        for (int j = 1, x; j <= cnt && i * pr[j] <= 5e4; j++) {
            vis[x = i * pr[j]] = 1;
            if (i % pr[j] == 0) { mu[x] = 0; break; }
            mu[x] = -mu[i];
        }
    }
    for (int i = 1; i <= 5e4; i++) s[i] = s[i - 1] + mu[i];
    scanf("%d", &Ti);
    while (Ti--) {
        scanf("%d%d%d", &n, &m, &K);
        n /= K, m /= K;
        if (n > m) swap(n, m);
        res = 0;
        for (int l = 1, r; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            res += (s[r] - s[l - 1]) * (n / l) * (m / l);
        }
        printf("%d\n", res);
    }
}

[SDOI2015] 约数个数和

\(\sum_{i=1}^n\sum_{j=1}^m\sigma_0(ij)\)

重要性质:\(\sigma_0(ij)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1]\)

证明:

接下来推导

\[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^m\sigma_0(ij)&= \sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1]\\ &=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}\sum_{d|\gcd(x,y)}\mu(d)\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\sum_{d|x}\sum_{d|y}\sum_{x|i}\sum_{y|j}1\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\sum_{d|x}\sum_{d|y} \lfloor\dfrac n x\rfloor\lfloor\dfrac m y\rfloor\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)\sum_{x=1}^{\lfloor\frac n d\rfloor} \sum_{y=1}^{\lfloor\frac m d\rfloor}\lfloor\dfrac{n}{dx}\rfloor \lfloor\dfrac{m}{dy}\rfloor\\ &=\sum_{d=1}^{\min(n,m)}\mu(d)f(\lfloor\dfrac{n}{d}\rfloor)f(\lfloor\dfrac{m}{d}\rfloor) \end{aligned} \]

其中 \(f(n)=\sum_{i=1}^n\lfloor\dfrac{n}{i}\rfloor\)

\(n,m\le 50000\) ,其实直接暴力求即可。

由于

\[f(n)=\sum_{i=1}^n\lfloor\dfrac{n}{i}\rfloor= \sum_{i=1}^n\sum_{i|d}1=\sum_{d=1}^n\sigma_0(d) \]

所以 \(f\) 是可以线性筛的。此处用暴力实现

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
typedef long double LD;
typedef long long LL;
typedef double db;
const int N = 50005;
int Ti, n, m, pr[N], cnt, mu[N], sm[N];
LL ans, dv[N];
bitset<N> vis;
int main() {
    mu[1] = 1;
    for (int i = 2; i <= 50000; i++) {
        if (!vis[i]) pr[++cnt] = i, mu[i] = -1;
        for (int j = 1, x; j <= cnt && i * pr[j] <= 50000; j++) {
            x = i * pr[j], vis[x] = 1;
            if (i % pr[j]) mu[x] = -mu[i];
            else { mu[x] = 0; break; }
        }
    }
    for (int i = 1; i <= 50000; i++) {
        sm[i] = sm[i - 1] + mu[i];
        for (int l = 1, r; l <= i; l = r + 1) {
            r = i / (i / l);
            dv[i] += 1ll * (r - l + 1) * (i / l);
        }
    }
    scanf("%d", &Ti);
    for (; Ti--; ) {
        scanf("%d%d", &n, &m);
        if (n > m) n ^= m ^= n ^= m;
        ans = 0;
        for (int l = 1, r; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            ans += dv[n / l] * dv[m / l] * (sm[r] - sm[l - 1]);
        }
        printf("%lld\n", ans);
    }
}

[国家集训队]Crash的数字表格

\(\sum_{i=1}^n\sum_{j=1}^m\text{lcm}(i,j)\)

基本上比较套路地推导,尝试几遍就可以了

此处假设 \(n\le m\)

\[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^m\text{lcm}(i,j)&= \sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^m\dfrac{ij}{d}[\gcd(i,j)=d]\\ &=\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} i\cdot j\cdot d[\gcd(i,j)=1]\\ &=\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} i\cdot j\cdot d\sum_{k|\gcd(i,j)}\mu(k)\\ &=\sum_{d=1}^n\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)\sum_{i=1}^{\lfloor\frac{n}{dk}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{dk}\rfloor} ik\cdot jk\cdot d\\ &=\sum_{d=1}^n d\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)*k^2\sum_{i=1}^{\lfloor\frac{n}{dk}\rfloor}i\sum_{j=1}^{\lfloor\frac{m}{dk}\rfloor} j \end{aligned} \]

\(f(x)=\sum_{i=1}^x i\) ,进一步化为

\[\sum_{d=1}^n d\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k)*k^2*f(\lfloor\dfrac{n}{dk}\rfloor)*f(\lfloor\dfrac{m}{dk}\rfloor) \]

此时已经可以用两个整除嵌套分块完成 \(O(n)\) 的做法。

这里还有一个常见套路:令 \(T=dk\) ,并枚举 \(T\)

\[\begin{aligned} &=\sum_{T=1}^n f(\lfloor\dfrac{n}{T}\rfloor)*f(\lfloor\dfrac{m}{T}\rfloor) \sum_{d|T} d*\mu(\dfrac{T}{d})*(\dfrac{T}{d})^2\\ &=\sum_{T=1}^n f(\lfloor\dfrac{n}{T}\rfloor)*f(\lfloor\dfrac{m}{T}\rfloor) \sum_{d|T} \mu(d)*d^2*\dfrac{T}{d}\\ &=\sum_{T=1}^n f(\lfloor\dfrac{n}{T}\rfloor)*f(\lfloor\dfrac{m}{T}\rfloor) *T\sum_{d|T} \mu(d)*d \end{aligned} \]

看后面这一个 \(T\sum_{d|T}\mu(d)*d\) ,设函数 \(F(T)=\sum_{d|T}\mu(d)*d\) ,要求 \(T*F(T)\) 的前缀和

\(F(T)\) 显然是积性函数。

考虑 \(F(p^k)=\sum_{i=0}^k\mu(p^i)*p^i\)

由于在 \(i\ge 2\)\(\mu(p^i)=0\) ,所以 \(F(p^k)=\mu(p^0)*p^0+\mu(p^1)*p^1=1-p\) ,可以 \(O(1)\)

所以 \(F\) 可以线性筛。枚举 \(x\) 和质数 \(p\)

  • \(x\perp p\)\(F(xp)=F(x)F(p)\)
  • 否则,\(\mu(xp)=0\)\(F(xp)=\sum_{d|xp}\mu(d)*d=\mu(xp)*xp+F(x)=F(x)\)

一个数论分块即可,\(O(\sqrt n)\)

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
typedef long double LD;
typedef long long LL;
typedef double db;
const LL P = 20101009;
const int N = 1e7 + 5;
int n, m, vis[N], pr[N], cnt;
LL f[N], res;
inline LL S(int n) { return 1ll * n * (n + 1) / 2 % P; }
int main() {
    f[1] = 1;
    for (int i = 2; i <= 1e7; i++) {
        if (!vis[i]) pr[++cnt] = i, f[i] = (P + 1 - i) % P;
        for (int j = 1, x; j <= cnt && i * pr[j] <= 1e7; j++) {
            vis[x = i * pr[j]] = 1;
            if (i % pr[j] == 0) { f[x] = f[i]; break; }
            f[x] = f[i] * f[pr[j]] % P;
        }
    }
    for (int i = 2; i <= 1e7; i++) f[i] = (f[i] * i % P + f[i - 1]) % P;
    scanf("%d%d", &n, &m);
    res = 0;
    if (n > m) n ^= m ^= n ^= m;
    for (int l = 1, r; l <= n; l = r + 1) {
        r = min(n / (n / l), m / (m / l));
        (res += S(n / l) * S(m / l) % P * (f[r] - f[l - 1] + P) % P) %= P;
    }
    printf("%lld", res);
}

总结

  • 对于 \(\gcd\) 的问题用 \(\sum_{d|n}\mu(d)=[n=1]\) 能解决大部分

  • 常见套路

    1. 枚举 \(\gcd\)
    2. 枚举倍数
    3. 和式变化,约数项提到前面
    4. 换元,再提到前面
  • 一种形式(假设 \(n\le m\)

    \[\begin{aligned} \sum_{i=1}^n\sum_{j=1}^mf(\gcd(i,j))&= \sum_{d=1}^{n}\sum_{i=1}^n\sum_{j=1}^m f(d)[\gcd(i,j)=d]\\ &=\sum_{d=1}^{n}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} f(d)[\gcd(i,j)=1]\\ &=\sum_{d=1}^{n}f(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} \sum_{k|\gcd(i,j)}\mu(k)\\ &=\sum_{d=1}^{n}f(d)\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k) \sum_{i=1}^{\lfloor\frac{n}{dk}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{dk}\rfloor}1\\ &=\sum_{d=1}^{n}f(d)\sum_{k=1}^{\lfloor\frac{n}{d}\rfloor}\mu(k) \lfloor\dfrac{n}{dk}\rfloor\lfloor\dfrac{m}{dk}\rfloor \end{aligned} \]

    还是令 \(T=dk\)

    \[\sum_{T=1}^n\lfloor\dfrac{n}{T}\rfloor\lfloor\dfrac{m}{T}\rfloor \sum_{d|T}f(d)\mu(\dfrac{T}{d}) \]

  • 多加练习,找到感觉

posted @ 2022-06-16 19:12  小蒟蒻laf  阅读(57)  评论(0编辑  收藏  举报