数论进阶——莫比乌斯反演

莫比乌斯反演

前言

本文参考pengym的莫比乌斯反演,讲得极好

莫比乌斯函数

定义

对于整数 d d d,我们先对其进行质因数分解:
d = ∏ i = 1 m p i k i d = \prod_{i=1}^{m} p_i^{k_i} d=i=1mpiki其中 p i p_i pi为互不相等的质数,以此为前提,莫比乌斯函数 μ ( d ) \mu(d) μ(d)的定义是:
μ ( d ) = { 1 i f   d = 1 ( − 1 ) m i f   ∀ i ∈ { 1 , 2 , ⋯   , m } ,   k i = 1 0 i f   ∃ i ∈ { 1 , 2 , ⋯   , m } ,   k i > = 2 \mu(d) = \begin{cases} {} 1 & if \ d =1 \\ (-1)^m & if\ \forall i \in \left\{1, 2,\cdots,m\right\},\ k_i =1\\ 0 & if\ \exist i\in \left\{1,2,\cdots,m\right\},\ k_i >= 2 \end{cases} μ(d)=1(1)m0if d=1if i{1,2,,m}, ki=1if i{1,2,,m}, ki>=2用人话说就是如果 d d d等于1,莫比乌斯函数 μ ( d ) \mu(d) μ(d)的值就是1;如果 d d d分解得到的质因数的幂次都是1,则 μ ( d ) \mu(d) μ(d)由分解得到的质因数的个数决定;否则如果存在某个质因数的幂次大于等于2,则 μ ( d ) = 0 \mu(d)=0 μ(d)=0
很容易看出所有质数 p p p μ ( p ) = − 1 \mu(p)=-1 μ(p)=1

性质

由于笔者的水平十分有限,下面只列出了笔者理解了的三个性质,有没有其他性质笔者也没有深入了解,如果有读者还了解其他性质,欢迎在评论区留言说的会有人看一样

  • 对于 ∀ n ∈ N + \forall n \in N^+ nN+,有
    ∑ d ∣ n μ ( d ) = [ n = = 1 ] , \sum_{d|n} \mu(d)=[n==1], dnμ(d)=[n==1], 可以把 [ n = = 1 ] [n==1] [n==1]看作为一个布尔表达式,它返回 t r u e true true f a l s e false false,只有当 n = 1 n=1 n=1时, n n n的因数的莫比乌斯函数之和为1,否则和为0

    瞎*儿证明一下:

    因为 n = p 1 k 1 ∗ p 2 k 2 ∗ ⋯ ∗ p m k m n=p_1^{k_1}*p_2^{k_2}*\cdots*p_m^{k_m} n=p1k1p2k2pmkm,哪些数是 n n n的因数呢?我们可以这么想,对于质因数 p i p_i pi,我们可以取 0 , 1 , 2 , ⋯   , k i 0,1,2,\cdots,k_i 0,1,2,,ki个,所以 n n n ( k 1 + 1 ) ∗ ( k 2 + 1 ) ∗ ⋯ ∗ ( k m + 1 ) (k_1+1)*(k_2+1)*\cdots*(k_m+1) (k1+1)(k2+1)(km+1)个因数,也就是说 T 1 T_1 T1式子中的 d d d ( k 1 + 1 ) ∗ ( k 2 + 1 ) ∗ ⋯ ∗ ( k m + 1 ) (k_1+1)*(k_2+1)*\cdots*(k_m+1) (k1+1)(k2+1)(km+1)这么多种取值,而我们要求这些 d d d对应的 μ \mu μ值再对它们求和。
    根据 μ ( x ) \mu(x) μ(x)的定义,任何质因数的幂次大于等于2时, μ ( x ) = 0 \mu(x)=0 μ(x)=0,也就是说每个质因数我们最多取一次,因为取两次或以上得到的 μ \mu μ为0,不会对求和产生影响。我们令 Y = p 1 ∗ p 2 ∗ ⋯ ∗ p m Y=p_1*p_2*\cdots*p_m Y=p1p2pm,则 ∑ d ∣ n μ ( d ) = 1 ∗ C m 0 + ( − 1 ) 1 ∗ C m 1 + ⋯ + ( − 1 ) m ∗ C m m \sum\limits_{d|n}\mu(d) = 1*C_m^{0} + (-1)^1*C_m^1+\cdots+(-1)^m*C_m^m dnμ(d)=1Cm0+(1)1Cm1++(1)mCmm,由二项式定理我们可得 1 ∗ C m 0 + ( − 1 ) 1 ∗ C m 1 + ⋯ + ( − 1 ) m ∗ C m m = ( − 1 + 1 ) m = 0 m 1*C_m^{0} + (-1)^1*C_m^1+\cdots+(-1)^m*C_m^m = (-1 +1)^m=0^m 1Cm0+(1)1Cm1++(1)mCmm=(1+1)m=0m,当 m = 0 m=0 m=0时,即 n = 1 n=1 n=1时, ∑ d ∣ n μ ( d ) = 1 \sum\limits_{d|n}\mu(d)=1 dnμ(d)=1;其他情况 ∑ d ∣ n μ ( d ) = 0 \sum\limits_{d|n}\mu(d)=0 dnμ(d)=0

  • 莫比乌斯函数 μ ( d ) \mu(d) μ(d)是积性函数,即若 gcd ⁡ ( n , m ) = 1 \gcd(n,m)=1 gcd(n,m)=1,则 μ ( n m ) = μ ( n ) μ ( m ) \mu(nm)=\mu(n)\mu(m) μ(nm)=μ(n)μ(m),这个性质用定义稍微想想就出来了

  • 对于 ∀ n ∈ N + \forall n \in N^+ nN+,有
    ∑ d ∣ n μ ( d ) d = φ ( n ) n , \sum_{d|n} \frac{\mu(d)}{d}=\frac{\varphi(n)}{n}, dndμ(d)=nφ(n), 其中 φ ( n ) \varphi(n) φ(n)是欧拉函数,定义是 [ 1 , n − 1 ] [1,n-1] [1,n1]内与 n n n互质数的个数

    瞎*儿证明一下:
    欧拉函数有一个性质:

    φ ( n ) = n ∗ ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) ∗ ⋯ ∗ ( 1 − 1 p m ) \varphi(n) = n * (1-\frac{1}{p_1}) * (1-\frac{1}{p_2})*\cdots*(1-\frac{1}{p_m}) φ(n)=n(1p11)(1p21)(1pm1) (PS:关于这个性质的理解可以移步数论初步,不过那篇巨长,读者可以去欧拉定理那块去找

    有了这一性质就好办了,右式
    φ ( n ) n = ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) ∗ ⋯ ∗ ( 1 − 1 p m ) \frac{\varphi(n)}{n}=(1-\frac{1}{p_1}) * (1-\frac{1}{p_2})*\cdots*(1-\frac{1}{p_m}) nφ(n)=(1p11)(1p21)(1pm1) 关于左边的和式中 d d d,每个质因数最多选一次,因为取两次或以上相乘得到的 d d d的莫比乌斯函数 μ ( d ) = 0 \mu(d)=0 μ(d)=0,再根据 μ ( d ) \mu(d) μ(d)的定义可以得到下面的式子
    ∑ d ∣ n μ ( d ) d = 1 + ( − 1 ) 1 ∗ ( 1 p 1 + 1 p 2 + ⋯ + 1 p m ) + ( − 1 ) 2 ∗ ( 1 p 1 p 2 + 1 p 1 p 3 + ⋯ + 1 p 1 p m + 1 p 2 p 3 + 1 p 2 p 4 + ⋯ + 1 p m − 1 p m ) + ⋯ + ( − 1 ) m ∗ 1 p 1 p 2 ⋯ p m \sum_{d|n} \frac{\mu(d)}{d}=1+(-1)^1*(\frac{1}{p_1}+\frac{1}{p_2}+\cdots+\frac{1}{p_m})\\+(-1)^2*(\frac{1}{p_1p_2}+\frac{1}{p_1p_3}+\dots+\frac{1}{p_1p_m}+\frac{1}{p_2p_3}+\frac{1}{p_2p_4}+\cdots +\frac{1}{p_{m-1}p_m})\\+\cdots+(-1)^m*\frac{1}{p_1p_2 \cdots p_m} dndμ(d)=1+(1)1(p11+p21++pm1)+(1)2(p1p21+p1p31++p1pm1+p2p31+p2p41++pm1pm1)++(1)mp1p2pm1 稍微想想就能发现上面两个式子其实就是相等的,于是这个性质也口糊完了

线性筛莫比乌斯函数

基本上是根据定义筛出来的,和性质没啥大的关系

void get_mu(int n) {
    mu[1] = 1; check[1] = true;
    for(int i = 2; i <= n; i++) {
        if(!check[i])
            prime[++tot] = i, mu[i] = -1;
        for(int j = 1; j <= tot && i * prime[j] <= n; j++) {
			check[i * prime[j]] = 1;
            if(i % prime[j]) mu[i * prime[j]] = -mu[i];
            else {
                mu[i * prime[j]] = 0;
                break;
            }
        }
    }
}

莫比乌斯反演

终于到了本文的重点,莫比乌斯反演定理当然前面的内容也很重要

定理内容

F ( n ) F(n) F(n) f ( n ) f(n) f(n)为定义在正整数集合上的两个函数,如果它们满足
F ( n ) = ∑ d ∣ n f ( d ) = ∑ d ∣ n f ( n d ) F(n)=\sum_{d|n}f(d)=\sum_{d|n}f(\frac{n}{d}) F(n)=dnf(d)=dnf(dn)那么可得
f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) = ∑ d ∣ n μ ( n d ) F ( d ) f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})=\sum_{d|n}\mu(\frac{n}{d})F(d) f(n)=dnμ(d)F(dn)=dnμ(dn)F(d)而且这个条件是充要的

在看证明之前可以先列几项感受一下:
f ( 1 ) = F ( 1 ) F ( 1 ) = f ( 1 ) f ( 2 ) = F ( 2 ) − F ( 1 ) F ( 2 ) = f ( 1 ) + f ( 2 ) f ( 3 ) = F ( 3 ) − F ( 1 ) F ( 3 ) = f ( 1 ) + f ( 3 ) f ( 4 ) = F ( 4 ) − F ( 2 ) F ( 4 ) = f ( 1 ) + f ( 2 ) + f ( 4 ) ⋮ ⋮ \begin{array}{c|c} f(1)=F(1) & F(1)=f(1)\\ f(2)=F(2)-F(1) & F(2)=f(1)+f(2)\\ f(3)=F(3)-F(1) & F(3)=f(1)+f(3)\\ f(4)=F(4)-F(2) & F(4)=f(1)+f(2)+f(4)\\ \vdots & \vdots \end{array} f(1)=F(1)f(2)=F(2)F(1)f(3)=F(3)F(1)f(4)=F(4)F(2)F(1)=f(1)F(2)=f(1)+f(2)F(3)=f(1)+f(3)F(4)=f(1)+f(2)+f(4)

证明

充分性

由已知条件
F ( n ) = ∑ d ∣ n f ( d ) = ∑ d ∣ n f ( n d ) F(n)=\sum_{d|n}f(d)=\sum_{d|n}f(\frac{n}{d}) F(n)=dnf(d)=dnf(dn)所以
∑ d ∣ n μ ( d ) F ( n d ) ( 1 ) = ∑ d ∣ n ( μ ( d ) ∑ i ∣ n d f ( i ) ) ( 2 ) = ∑ d ∣ n ∑ i ∣ n d μ ( d ) f ( i ) ( 3 ) = ∑ i ∣ n ∑ d ∣ n i μ ( d ) f ( i ) ( 4 ) = ∑ i ∣ n ( f ( i ) ∑ d ∣ n i μ ( d ) ) ( 5 ) \begin{array}{cc} \sum\limits_{d|n}\mu(d)F(\frac{n}{d}) & (1)\\[.5cm] =\sum\limits_{d|n}(\mu(d)\sum\limits_{i|\frac{n}{d}}f(i)) & (2)\\[.5cm] =\sum\limits_{d|n}\sum\limits_{i|\frac{n}{d}}\mu(d)f(i) & (3)\\[.5cm] =\sum\limits_{i|n}\sum\limits_{d|\frac{n}{i}}\mu(d)f(i) & (4)\\[.5cm] =\sum\limits_{i|n}(f(i)\sum\limits_{d|\frac{n}{i}}\mu(d)) & (5) \end{array} dnμ(d)F(dn)=dn(μ(d)idnf(i))=dnidnμ(d)f(i)=indinμ(d)f(i)=in(f(i)dinμ(d))(1)(2)(3)(4)(5)PS:由(3)式推到(4)式可以想象一个二重循环,(4)式分别相当于把二重循环的内部循环拿出来变成外部循环,原来的外部循环变成内部循环,只是改变了一下求和的顺序,学过微积分的可以类比二重积分换序,没学过微积分就自行脑部吧

由莫比乌斯函数的第一条性质
∑ d ∣ n i μ ( d ) = [ n i = = 1 ] \sum_{d|\frac{n}{i}} \mu(d)=[\frac{n}{i}==1] dinμ(d)=[in==1]只有当 i = n i=n i=n时,才能使布尔表达式 [ n i = = 1 ] [\frac{n}{i}==1] [in==1]为真,使得 μ ( d ) = 1 \mu(d)=1 μ(d)=1,其他情况 μ ( d ) = 0 \mu(d)=0 μ(d)=0,也就是说
∑ i ∣ n ( f ( i ) ∑ d ∣ n i μ ( d ) ) = f ( n ) + 0 + 0 + ⋯ + 0 ⏟ n 的 因 数 个 数 − 1 = f ( n ) \sum_{i|n}(f(i)\sum_{d|\frac{n}{i}}\mu(d))=f(n)+\underbrace{0+0+\cdots+0}_{n的因数个数-1}=f(n) in(f(i)dinμ(d))=f(n)+n1 0+0++0=f(n)所以我们得到
∑ d ∣ n μ ( d ) F ( n d ) = f ( n ) \sum_{d|n}\mu(d)F(\frac{n}{d})=f(n) dnμ(d)F(dn)=f(n)

必要性

必要性的证明和充分性类似,限于篇幅,不予证明

回到莫比乌斯函数

看完莫比乌斯反演我们可以反过来看看上面莫比乌斯函数的第三条性质
∑ d ∣ n μ ( d ) d = φ ( n ) n \sum_{d|n} \frac{\mu(d)}{d}=\frac{\varphi(n)}{n} dndμ(d)=nφ(n)我们令 F ( n ) = n , f ( n ) = φ ( n ) F(n)=n,f(n)=\varphi(n) F(n)=n,f(n)=φ(n),由于欧拉函数有一个性质
n = ∑ d ∣ n φ ( d ) n=\sum_{d|n}\varphi(d) n=dnφ(d)也就是 F ( n ) = ∑ d ∣ n f ( d ) F(n)=\sum_{d|n}f(d) F(n)=dnf(d),那么由莫比乌斯反演定理,有
φ ( n ) = f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) = ∑ d ∣ n μ ( d ) n d \varphi(n)=f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})=\sum_{d|n}\mu(d)\frac{n}{d} φ(n)=f(n)=dnμ(d)F(dn)=dnμ(d)dn稍微移项就得到
∑ d ∣ n μ ( d ) d = φ ( n ) n \sum_{d|n} \frac{\mu(d)}{d}=\frac{\varphi(n)}{n} dndμ(d)=nφ(n)

例题

  • 洛谷P3455 ZAP-queries

    题意: 给定 n , m , d n,m,d n,m,d,问 ∑ x = 1 n ∑ y = 1 m [ g c d ( x , y ) = = d ] \sum\limits_{x=1}^n\sum\limits_{y=1}^m[gcd(x,y)==d] x=1ny=1m[gcd(x,y)==d] [ ] [] []里是一个布尔表达式
    思路(具体思路参考下一题的思路,下一题是本题的加强版): 不妨令 n ≤ m n\leq m nm,把 d d d除掉,记 n ′ = ⌊ n / d ⌋ , m ′ = ⌊ m / d ⌋ n'=\left\lfloor n/d\right\rfloor,m'=\left\lfloor m/d\right\rfloor n=n/d,m=m/d,原式化为 ∑ x = 1 n ′ ∑ y = 1 m ′ [ g c d ( x , y ) = = 1 ] \sum\limits_{x=1}^{n'}\sum\limits_{y=1}^{m'}[gcd(x,y)==1] x=1ny=1m[gcd(x,y)==1],式子化为
    ∑ x = 1 n ′ ∑ y = 1 m ′ ∑ d ∣ gcd ⁡ ( x , y ) μ ( d ) \sum_{x=1}^{n'}\sum_{y=1}^{m'}\sum_{d|\gcd(x,y)}\mu(d) x=1ny=1mdgcd(x,y)μ(d) d d d提前,原式化为
    ∑ d = 1 n ′ μ ( d ) ∗ ⌊ n ′ d ⌋ ∗ ⌊ m ′ d ⌋ \sum_{d=1}^{n'} \mu(d)*\left\lfloor \frac{n'}{d} \right\rfloor * \left\lfloor \frac{m'}{d} \right\rfloor d=1nμ(d)dndm注意到 ⌊ n ′ d ⌋ ∗ ⌊ m ′ d ⌋ \left\lfloor \frac{n'}{d} \right\rfloor * \left\lfloor \frac{m'}{d} \right\rfloor dndm可以数论分块(数论分块不会的话移步数论初步),只不过这里的每一块要求 ⌊ n ′ d ⌋ ∗ ⌊ m ′ d ⌋ \left\lfloor\frac{n'}{d}\right\rfloor*\left\lfloor\frac{m'}{d}\right\rfloor dndm相等,而 ∑ d = 1 n ′ μ ( d ) \sum\limits_{d=1}^{n'}\mu(d) d=1nμ(d)可以用前缀和 O ( 1 ) O(1) O(1)地求

    代码:

    #include 
    #include 
    const int N = 5e4+5;
    typedef long long ll;
    
    int n, m, d, tot;
    int prime[N >> 1], mu[N];
    ll sum[N];
    bool check[N];
    
    inline int min(int x, int y) { return x < y ? x : y; }
    
    void get_mu(int n) {
        mu[1] = 1; check[1] = true;
        for(int i = 2; i <= n; i++) {
            if(!check[i])
                prime[++tot] = i, mu[i] = -1;
            for(int j = 1; j <= tot && i * prime[j] <= n; j++) {
    			check[i * prime[j]] = 1;
                if(i % prime[j]) mu[i * prime[j]] = -mu[i];
                else {
                    mu[i * prime[j]] = 0;
                    break;
                }
            }
        }
        for(int i = 1; i <= n; i++)
            sum[i] = sum[i - 1] + mu[i];
    }
    
    ll calc() {
        ll res = 0;
        for(int l = 1, r = 0; l <= n; l = r + 1) {
            r = min((n / (n / l)), (m / (m / l)));
            res += (sum[r] -  sum[l - 1]) * (n / l) * (m / l);
        }
        return res;
    }
    
    int main() {
        int t; scanf("%d", &t);
        get_mu(N - 5);
        while(t--) {
            scanf("%d%d%d", &n, &m, &d);
            if(n > m) std::swap(n, m);
            n /= d, m /= d;
            printf("%lld\n", calc());
        }
        return 0;
    }
    
  • 洛谷 P2522 [HAOI]Problem b

    题意: 给定 a , b , c , d , k a,b,c,d,k a,b,c,d,k,问 ∑ x = a b ∑ y = c d [ g c d ( x , y ) = = k ] \sum\limits_{x=a}^b\sum\limits_{y=c}^d[gcd(x,y)==k] x=aby=cd[gcd(x,y)==k] [ ] [] []里是一个布尔表达式
    思路: 做完第一题后,这题基本就没啥东西了,我们可以利用容斥定理,
    a n s [ a , b ] [ c , d ] = a n s [ 1 , b ] [ 1 , d ] − a n s [ 1 , a − 1 ] [ 1 , b ] − a n s [ 1 , b ] [ 1 , c − 1 ] + a n s [ 1 , a − 1 ] [ 1 , c − 1 ] ans[a,b][c,d]=ans[1,b][1,d]-ans[1,a-1][1,b]\\-ans[1,b][1,c-1]+ans[1,a-1][1,c-1] ans[a,b][c,d]=ans[1,b][1,d]ans[1,a1][1,b]ans[1,b][1,c1]+ans[1,a1][1,c1] 然后调用四次第一题的函数就行了,需要注意的是区间左右端点除 k k k时需要处理一下,不能包含多余的左边界
    代码: 此题的main函数部分,其他部分基本不需要改动

    int main() {
        int t; scanf("%d", &t);
        get_mu(N - 5);
        while(t--) {
            scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
            if(a > b) std::swap(a, b);
            if(c > d) std::swap(c, d);
            if(a % k) {
                a /= k;
                a++;
            } else a /= k;
            if(c % k) {
                c /= k;
                c++;
            } else c /= k;
            b /= k, d /= k;
            printf("%lld\n", calc(b, d) - calc(a - 1, d) - calc(b, c - 1) + calc(a - 1, c - 1));
        }
        return 0;
    }
    
  • 洛谷P2257 YY的GCD

    题意: 给定 n , m n,m n,m,问 ∑ x = 1 n ∑ y = 1 m [ g c d ( x , y ) = = p r i m e ] \sum\limits_{x=1}^n\sum\limits_{y=1}^m[gcd(x,y)==prime] x=1ny=1m[gcd(x,y)==prime] [ ] [] []里是一个布尔表达式,其中 p r i m e prime prime是任意质数
    思路: 对于一个固定的质数,我们像上一题一样把它除掉就行了,姑且将这个质数记为 k k k,需要枚举 k k k,显然 k ≤ n k \leq n kn。令 n ≤ m n\leq m nm,记 P = { p   ∣   p   i s   p r i m e , p ≤ n } P=\left\{p\ |\ p\ is\ prime,p\leq n \right\} P={p  p is prime,pn},原式化为
    ∑ k ∈ P ∑ x = 1 ⌊ n / k ⌋ ∑ y = 1 ⌊ m / k ⌋ [ g c d ( x , y ) = = 1 ] \sum_{k\in P}\sum_{x=1}^{\left\lfloor n/k \right\rfloor}\sum_{y=1}^{\left\lfloor m/k \right\rfloor}[gcd(x,y)==1] kPx=1n/ky=1m/k[gcd(x,y)==1] 根据性质一
    ∑ d ∣ n μ ( d ) = [ n = = 1 ] \sum_{d|n}\mu(d)=[n==1] dnμ(d)=[n==1] 得到
    [ g c d ( x , y ) = = 1 ] = ∑ d ∣ gcd ⁡ ( x , y ) μ ( d ) [gcd(x,y)==1]=\sum\limits_{d|\gcd(x,y)}\mu(d) [gcd(x,y)==1]=dgcd(x,y)μ(d) 问题转化为求
    ∑ k ∈ P ∑ x = 1 ⌊ n / k ⌋ ∑ y = 1 ⌊ m / k ⌋ ∑ d ∣ gcd ⁡ ( x , y ) μ ( d ) \sum_{k\in P}\sum_{x=1}^{\left\lfloor n/k \right\rfloor}\sum_{y=1}^{\left\lfloor m/k \right\rfloor}\sum_{d|\gcd(x,y)}\mu(d) kPx=1n/ky=1m/kdgcd(x,y)μ(d) 将和式换序,由于 d ∈ [ 1 , n ] d \in [1,n] d[1,n],将 d d d提前后, i , j i,j i,j均为 d d d的倍数,原式进一步化简化为
    ∑ k ∈ P ∑ d = 1 ⌊ n / k ⌋ μ ( d ) ∗ ⌊ n k d ⌋ ∗ ⌊ m k d ⌋ \sum_{k\in P} \sum_{d=1}^{\left\lfloor n/k \right\rfloor} \mu(d)*\left\lfloor \frac{n}{kd} \right\rfloor * \left\lfloor \frac{m}{kd} \right\rfloor kPd=1n/kμ(d)kdnkdm k d = T kd=T kd=T 2 ≤ T ≤ n 2\leq T\leq n 2Tn,再将 T T T提前,先枚举 T T T,原式化为
    ∑ T = 2 n ⌊ n T ⌋ ∗ ⌊ m T ⌋ ∑ k ∣ T , k ∈ P μ ( T k ) \sum_{T=2}^{n}\left\lfloor \frac{n}{T} \right\rfloor * \left\lfloor \frac{m}{T} \right\rfloor \sum_{k|T,k\in P}\mu(\frac{T}{k}) T=2nTnTmkT,kPμ(kT) 注意到 ⌊ n T ⌋ ∗ ⌊ m T ⌋ \left\lfloor\frac{n}{T}\right\rfloor*\left\lfloor\frac{m}{T}\right\rfloor TnTm可以数论分块,关键在于我们要求出 ∑ k ∣ T , k ∈ P μ ( T k ) \sum\limits_{k|T,k\in P}\mu(\frac{T}{k}) kT,kPμ(kT)的前缀和,只要求出前缀和数组 s u m [ ] sum[] sum[],我们就能 O ( n ) O(\sqrt n) O(n )地算出上面的式子了
    s u m [ T ] = ∑ i = 1 T ∑ k ∣ i , k ∈ P μ ( i k ) sum[T]=\sum\limits_{i=1}^T \sum\limits_{k|i,k\in P} \mu(\frac{i}{k}) sum[T]=i=1Tki,kPμ(ki),记 ∑ k ∣ i , k ∈ P μ ( i k ) = g [ i ] \sum\limits_{k|i,k\in P} \mu(\frac{i}{k})=g[i] ki,kPμ(ki)=g[i],则 s u m [ i ] = s u m [ i − 1 ] + g [ i ] sum[i]=sum[i-1]+g[i] sum[i]=sum[i1]+g[i]。要求出 g [ i ] g[i] g[i],我们枚举每个质数 k k k,对每个质数枚举它的倍数,然后求和就行了

    细节看代码 ⇓ \Downarrow

    代码

    #include 
    #include 
    const int N = 1e7 + 5;
    typedef long long ll;
    
    int tot;
    int mu[N], prime[N >> 2];
    ll g[N], sum[N];
    bool check[N];
    
    void get_mu(int n) {
        mu[1] = 1; check[1] = true;
        for(ll i = 2; i <= n; i++) {
            if(!check[i])
                mu[i] = -1, prime[++tot] = i;
            for(int j = 1; j <= tot && i * prime[j] <= n; j++) {
                check[i * prime[j]] = true;
                if(i % prime[j]) mu[i * prime[j]] = -mu[i];
                else {
                    mu[i * prime[j]] = 0;
                    break;
                }
            }
        }
        for(int i = 1; i <= tot; i++)
            for(int j = 1; j * prime[i] <= n; j++)
                g[j * prime[i]] += (ll)mu[j];
        for(int i = 1; i <= n; i++)
            sum[i] = sum[i - 1] + g[i];
    }
    
    inline int min(int x, int y) { return x < y ? x : y; }
    
    ll calc(int n, int m) {
        ll res = 0L;
        for(int l = 1, r = 0; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            res += (sum[r] - sum[l - 1]) * (n / l) * (m / l);
        }
        return res;
    }
    
    int main() {
        get_mu(N - 5);
        int t;
        scanf("%d", &t);
        while(t--) {
            int n, m;
            scanf("%d%d", &n, &m);
            if(n > m) std::swap(n, m);
            printf("%lld\n", calc(n, m));
        }
        return 0;
    }
    

    总结: 大家可能感觉没莫比乌斯反演什么事情,用莫比乌斯函数的性质就能做,没有直接使用莫比乌斯反演,如果想看反演怎么做,可以查看洛谷的题解,最上面的一篇就是pengym写的,他的讲解很详细

    • (不定期更新例题大概

总结

莫比乌斯的代码一般都不是很长只是笔者没遇到巨长的题,工作量主要是推式子,如果能静下心来好好反演,应该可以做出来题不是
顺便推荐:An_Account的博客,有很多变式讲得很清楚

你可能感兴趣的:(ACM算法和数据结构专题)