莫比乌斯反演学习笔记

发布于:2025-08-10 ⋅ 阅读:(25) ⋅ 点赞:(0)

概念

莫比乌斯函数 μ ( n ) \mu(n) μ(n),是一个积性函数,定义为:
μ ( n ) = { 1 , n = 1 0 , n    i s    d i v i s i b l e    b y    t h e    s q u a r e    o f    a    p r i m e    n u m b e r ( − 1 ) k , k    i s    t h e    n u m b e r    o f    p r i m e    f a c t o r s    o f    n \mu(n)=\begin{cases}1,n=1\\ 0,n\;is\;divisible\;by\;the\;square\;of\;a\;prime\;number\\ (-1)^k,k\;is\;the\;number\;of\;prime\;factors\;of\;n \end{cases} μ(n)= 1,n=10,nisdivisiblebythesquareofaprimenumber(1)k,kisthenumberofprimefactorsofn

其性质有:一、 ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1] dnμ(d)=[n=1];二、 μ ∗ 1 = ϵ \mu*1=\epsilon μ1=ϵ,其中 ∗ * 表示狄利克雷卷积, ϵ = [ n = 1 ] \epsilon=[n=1] ϵ=[n=1](其实这条与一等价)

莫比乌斯反演的形式有二:一、设 F ( n ) = ∑ n ∣ m f ( m ) F(n)=\sum_{n|m}f(m) F(n)=nmf(m),有 f ( n ) = ∑ n ∣ m F ( m ) μ ( m n ) f(n)=\sum_{n|m}F(m)\mu(\frac{m}{n}) f(n)=nmF(m)μ(nm);二、设 F ( n ) = ∑ m ∣ n f ( m ) F(n)=\sum_{m|n}f(m) F(n)=mnf(m),有 f ( n ) = ∑ m ∣ n F ( n m ) μ ( m ) = ∑ m ∣ n F ( m ) μ ( n m ) f(n)=\sum_{m|n}F(\frac{n}{m})\mu(m)=\sum_{m|n}F(m)\mu(\frac{n}{m}) f(n)=mnF(mn)μ(m)=mnF(m)μ(mn)

例题

1. Luogu P2257 YY的GCD

题意

给定 N , M N, M N,M,求 1 ≤ x ≤ n 1 \leq x \leq n 1xn 1 ≤ y ≤ m 1 \leq y \leq m 1ym gcd ⁡ ( x , y ) \gcd(x, y) gcd(x,y) 为质数的 ( x , y ) (x, y) (x,y) 有多少对。

T = 1 0 4 ;    n , m ≤ 1 0 7 T = 10^4;\;n, m \leq 10^7 T=104;n,m107

做法

f ( p ) = ∑ x = 1 n ∑ y = 1 m [ gcd ⁡ ( x , y ) = p ] ; F ( p ) = ∑ p ∣ q f ( q ) = ⌊ n p ⌋ ⌊ m p ⌋ ; L = min ⁡ ( n , m ) f(p)=\sum_{x=1}^n\sum_{y=1}^m[\gcd(x, y)=p]; F(p)=\sum_{p|q}f(q)=\lfloor\frac{n}{p}\rfloor\lfloor\frac{m}{p}\rfloor; L=\min(n,m) f(p)=x=1ny=1m[gcd(x,y)=p];F(p)=pqf(q)=pnpm;L=min(n,m)

即求:

∑ p ∈ P r i m e f ( p ) = ∑ p ∈ P r i m e ∑ p ∣ x F ( x ) μ ( x p ) = ∑ p ∈ P r i m e ∑ i = 1 L / p ⌊ n i p ⌋ ⌊ m i p ⌋ μ ( i ) = ∑ T = 1 L ⌊ n T ⌋ ⌊ m T ⌋ ∑ p ∣ T    &    p ∈ P r i m e μ ( T p ) \sum_{p\in Prime}f(p)\\ =\sum_{p\in Prime}\sum_{p|x}F(x)\mu(\frac{x}{p})\\ =\sum_{p\in Prime}\sum_{i=1}^{L/p}\lfloor\frac{n}{ip}\rfloor\lfloor\frac{m}{ip}\rfloor\mu(i)\\ =\sum_{T=1}^{L}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{p|T\;\&\;p\in Prime}\mu(\frac{T}{p}) pPrimef(p)=pPrimepxF(x)μ(px)=pPrimei=1L/pipnipmμ(i)=T=1LTnTmpT&pPrimeμ(pT)

重点在于求 g ( x ) ≜ ∑ p ∣ x    &    p ∈ P r i m e μ ( x p ) g(x)\triangleq\sum_{p|x\;\&\;p\in Prime}\mu(\frac{x}{p}) g(x)px&pPrimeμ(px) p p p x x x 的一个质因数,考虑通过某种顺序枚举 x x x 的质因数,发现线性筛的过程会将 x x x 拆成一个最小的质因数和另一个数的乘积,即 x = y ⋅ p ,    p ∈ P r i m e x=y\cdot p,\;p\in Prime x=yp,pPrime,则有:
g ( x ) = { μ ( 1 ) ,    x ∈ P r i m e g ( y ) ,    p    i s    a    f a c t o r    o f    y − g ( y ) + μ ( y ) ,    p    i s    n o t    a    f a c t o r    o f    y    g(x)=\begin{cases}\mu(1),\;x\in Prime\\ g(y),\;p\;is\;a\;factor\;of\;y\\ -g(y)+\mu(y),\;p\;is\;not\;a\;factor\;of\;y\;\end{cases} g(x)= μ(1),xPrimeg(y),pisafactorofyg(y)+μ(y),pisnotafactorofy
需要注意从 − g ( y ) -g(y) g(y) 转移因为 g ( y ) g(y) g(y) 所包含的 μ \mu μ g ( x ) g(x) g(x) 所包含的 μ \mu μ 差一个因子 p p p

代码
#include <bits/stdc++.h>

const int N = 1e7;

int mu[N + 2], prime[N + 2], top, sum[N + 2];
bool nprime[N + 2];

void solve() {
    int n, m;
    std::cin >> n >> m;
    long long ans = 0;
    for (int l = 1, r; l <= std::min(n, m); l = r + 1) {
        r = std::min(n / (n / l), m / (m / l));
        ans += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]);
    }
    std::cout << ans << '\n';
}

int main() {
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
    mu[1] = 1;
    for (int i = 2; i <= N; i++) {
        if (!nprime[i]) {
            prime[++top] = i;
            mu[i] = -1;
            sum[i] = 1;
        }
        for (int j = 1; j <= top && 1ll * i * prime[j] <= N; j++) {
            int now = i * prime[j];
            nprime[now] = 1;
            if (i % prime[j] == 0) {
                mu[now] = 0;
                sum[now] = mu[i];
                break;
            }
            mu[now] = -mu[i];
            sum[now] = mu[i] - sum[i];
        }
    }
    for (int i = 1; i <= N; i++) {
        sum[i] += sum[i - 1];
    }
    int t;
    std::cin >> t;
    while (t--) {
        solve();
    }
}

2. Luogu P2522 [HAOI2011] Problem b

题意

对于给出的 n n n 个询问,每次求有多少个数对 ( x , y ) (x,y) (x,y),满足 a ≤ x ≤ b a \le x \le b axb c ≤ y ≤ d c \le y \le d cyd,且 gcd ⁡ ( x , y ) = k \gcd(x,y) = k gcd(x,y)=k

1 ≤ n , k ≤ 5 × 1 0 4 1 \le n,k \le 5 \times 10^4 1n,k5×104 1 ≤ a ≤ b ≤ 5 × 1 0 4 1 \le a \le b \le 5 \times 10^4 1ab5×104 1 ≤ c ≤ d ≤ 5 × 1 0 4 1 \le c \le d \le 5 \times 10^4 1cd5×104

做法

(这个感觉比上面一个更加板子)

可以 a ′ ← ⌈ a k ⌉ ,    b ′ ← ⌊ b k ⌋ a'\gets\lceil\frac{a}{k}\rceil,\;b'\gets\lfloor\frac{b}{k}\rfloor aka,bkb 这样操作把 k k k 转换为 1 1 1,然后对于两个区间可以容斥为 r e s ( b ′ , d ′ ) − r e s ( a ′ − 1 , d ′ ) − r e s ( b ′ , c ′ − 1 ) + r e s ( a ′ − 1 , c ′ − 1 ) res(b',d')-res(a'-1,d')-res(b',c'-1)+res(a'-1,c'-1) res(b,d)res(a1,d)res(b,c1)+res(a1,c1)。即求 ∑ x = 1 n ∑ y = 1 m [ gcd ⁡ ( x , y ) = 1 ] = ∑ i = 1 min ⁡ ( n , m ) ⌊ n i ⌋ ⌊ m i ⌋ μ ( i ) \sum_{x=1}^{n}\sum_{y=1}^{m}{[\gcd(x,y)=1]}=\sum_{i=1}^{\min(n,m)}\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor\mu(i) x=1ny=1m[gcd(x,y)=1]=i=1min(n,m)inimμ(i)

代码
#include <bits/stdc++.h>

const int N = 5e4;

int mu[N + 2], prime[N + 2], top, sum[N + 2];
bool nprime[N + 2];

long long work(int n, int m) {
    long long ans = 0;
    if (n > m) {
        std::swap(n, m);
    }
    for (int l = 1, r; l <= n; l = r + 1) {
        r = std::min(n / (n / l), m / (m / l));
        ans += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]);
    }
    return ans;
}

void solve() {
    int a, b, c, d, k;
    std::cin >> a >> b >> c >> d >> k;
    a = (a + k - 1) / k;
    c = (c + k - 1) / k;
    b = b / k;
    d = d / k;
    std::cout << (work(b, d) - work(a - 1, d) - work(b, c - 1) + work(a - 1, c - 1)) << '\n';
}

int main() {
    std::ios::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
    mu[1] = 1;
    for (int i = 2; i <= N; i++) {
        if (!nprime[i]) {
            prime[++top] = i;
            mu[i] = -1;
        }
        for (int j = 1; j <= top && 1ll * i * prime[j] <= N; j++) {
            int now = i * prime[j];
            nprime[now] = 1;
            if (i % prime[j] == 0) {
                mu[now] = 0;
                break;
            }
            mu[now] = -mu[i];
        }
    }
    for (int i = 1; i <= N; i++) {
        sum[i] = sum[i - 1] + mu[i];
    }
    int t;
    std::cin >> t;
    while (t--) {
        solve();
    }
}