浅谈莫比乌斯反演

· · 个人记录

这可能是我写过最正经的一篇博客吧

先来看一个例子

ans = \sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j),求 ans

1 \leq n , m \leq 10^3

你可能会说,这不是简单吗,暴力枚举 i,j , 然后统计答案就好了啊

当如果我改一下题目呢?

ans = \sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)T组询问,对于每组询问,求 ans

1 \leq n , m \leq 10^5 , 1 \leq T \leq 10^5

这就不是暴力能解决了的

所以我们来引进一个新算法,那就是——莫比乌斯反演

数论函数

积性函数

这里列举几个常用的积性函数,对做题很有帮助:

这里通俗解释一下这些函数分别是什么意思

狄利克雷卷积

定义:

性质:

这里列举几个常用的狄利克雷卷积:

前两个就不做证明了,带入具体值都是可以得到的

第三个证明呢?我们在原式两边同时卷上一个I,就得到

\varphi \times I = \mu \times \varepsilon \times I

根据前两个式子,我们可以得到

\varepsilon = e \times \varepsilon

根据原函数e的定义,任何数论函数卷e都等于自己

所以这个式子是成立的

根据以上的定义,我们已经可以做莫比乌斯反演了

莫比乌斯反演

本质:

这里列举两个套路:

这两个的套路是根据狄利克雷卷积的性质,将gcd(i,j)当做n带入即可

就这么简单

怎么求出\mu

前面我们已经说过了,\mu是一个积性函数,所以我们可以用线性筛求出来

我们分析一下,对于一个质数p

inline void GetMiu(int n) {
    vis[0] = vis[1] = true; mu[1] = 1;
    for(R int i=2; i<=n; i++) {
        if(!vis[i]) pri[++tot] = i , mu[i] = -1;
        for(R int j=1; j<=tot&&i*pri[j]<=n; j++) {
            vis[i*pri[j]] = true;
            if(i%pri[j])    mu[i*pri[j]] = -mu[i];
            else    { mu[i*pri[j]] = 0; break; }
        }
    }
}

讲了这么多,我们来做几道题练练手吧

洛谷P2522 [HAOI2011]Problem b

题目大意:求当 i \in [a,b] , j \in [c,d],满足gcd(i,j) = k的数对(i,j)的个数

推莫比乌斯反演的时候,不要慌,先把式子列出来再说

另题目所求的答案 = ans,则

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

首先我们来定义一个函数ff(n,m) = \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==k]

那么这个ans显然可以容斥对吧

那么ans = f(c,d) - f(a-1,d) - f(b,c-1) + f(a-1,c-1)

懂了吗???肯定懂了!

如果你还不懂的话,把这个问题理解为:

你有一个b\times d的矩形,求右下角那个(b-a+1)\times (d-c+1)的矩形面积

然后题目的答案显然是:

现在懂了吧

于是我们只需要求f(n,m)就行了,到时候a,b,c,d什么的分别当做n,m带入就行了

f(n,m) = \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==k]

首先,我们知道,如果gcd(i,j) == k,那么gcd(\frac{i}{k},\frac{j}{k}) == 1(这是一个定理,背背背背背背)

这说明了i,j一定是k的倍数,那么我们不妨设i=k\times x , j = k \times y(这里采用了换元的思想)

则:f(n,m) = \sum_{kx=1}^{n}\sum_{ky=1}^{m}[gcd(kx,ky)==k]

化简一下:f(n,m) = \sum_{x=1}^{\lfloor \frac{n}{k} \rfloor}\sum_{y=1}^{\lfloor \frac{m}{k} \rfloor}[gcd(x,y)==1]

哇,看着x,y不舒服,我们还是把i,j换回来吧,当然此i,j非一开始的那个i,j

f(n,m) = \sum_{i=1}^{\lfloor \frac{n}{k} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{k} \rfloor}[gcd(i,j)==1]

看到[gcd(i,j)==1],我们立马转莫比乌斯函数\mu

f(n,m) = \sum_{i=1}^{\lfloor \frac{n}{k} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{k} \rfloor}\sum_{d|gcd(i,j)}\mu(d)

这里提一下,d|gcd(i,j) = d|i 并且 d|j

我们把这个d给提到前面去

f(n,m) = \sum_{d=1}^{min(\lfloor \frac{n}{k} \rfloor,\lfloor \frac{m}{k} \rfloor)}\mu(d)\sum_{d|i}^{\lfloor \frac{n}{k} \rfloor}\sum_{d|j}^{\lfloor \frac{m}{k} \rfloor}

我们可以发发现,对于d|i , d|j,我们依旧可以还原,枚举id,jd,于是原式又变成了

f(n,m) = \sum_{d=1}^{min(\lfloor \frac{n}{k} \rfloor,\lfloor \frac{m}{k} \rfloor)}\mu(d)\sum_{id}^{\lfloor \frac{n}{k} \rfloor}\sum_{jd}^{\lfloor \frac{m}{k} \rfloor}

化简一下

f(n,m) = \sum_{d=1}^{min(\lfloor \frac{n}{k} \rfloor,\lfloor \frac{m}{k} \rfloor)}\mu(d)\sum_{i=1}^{\lfloor \frac{n}{kd} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{kd} \rfloor} f(n,m) = \sum_{d=1}^{min(\lfloor \frac{n}{k} \rfloor,\lfloor \frac{m}{k} \rfloor)}\mu(d) \lfloor \frac{n}{kd} \rfloor \lfloor \frac{m}{kd} \rfloor

这就是最终式子了

至于这个式子,将\mu做一个前缀和,利用数论分块的思想来做

inline int Mobius(int n , int m , int k) {
    if(n > m)   swap(n,m);
    n /= k , m /= k; R int ans = 0;
    for(R int i=1; i<=n; i=j+1) {
        i = min( n / (n/i) , m / (m/i) );
        ans += ( SumMu[j] - SumMu[i-1] ) * ( n / i ) * ( m / i );
    }
    return ans;
}

时间复杂度是O(\sqrt{n})的,我们就可以愉快的满足那险恶的T组询问了

怎么样,代码就这么短,就是这么好写

洛谷P1829 [国家集训队]Crash的数字表格 / JZPTAB

题目大意:求\sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)

这道题的详解,我以前已经写过一次了

没看过的可以戳下面qwq

传送门

我在这里就简单的把式子列出来一下吧

lcm(i,j) = \frac{ij}{gcd(i,j)} ans = \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) \space \space \space \space \space \space \space = \sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{gcd(i,j)} \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}\frac{1}{d}\sum_{d|i}\sum_{d|j}i\times j[gcd(i,j)==d] \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}\frac{1}{d}\sum_{id=1}^{n}\sum_{jd=1}^{m}id\times jd[gcd(id,jd)==d] \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}d\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{d} \rfloor}i\times j[gcd(i,j)==1] \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}d\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{d} \rfloor}i\times j\sum_{p|i,j}\mu(p) \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min(\lfloor \frac{n}{d} \rfloor,\lfloor \frac{m}{d} \rfloor)}\mu(p)\sum_{p|i}\sum_{p|j}i\times j \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min(\lfloor \frac{n}{d} \rfloor,\lfloor \frac{m}{d} \rfloor)}\mu(p)\sum_{ip=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{jp=1}^{\lfloor \frac{m}{d} \rfloor}ip\times jp \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min(\lfloor \frac{n}{d} \rfloor,\lfloor \frac{m}{d} \rfloor)}\mu(p)p^{2}\times \sum_{i=1}^{\lfloor \frac{n}{dp} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{dp} \rfloor}i\times j \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min(\lfloor \frac{n}{d} \rfloor,\lfloor \frac{m}{d} \rfloor)}\mu(p)p^{2}\times \sum_{i=1}^{\lfloor \frac{n}{dp} \rfloor}i\sum_{j=1}^{\lfloor \frac{m}{dp} \rfloor}j \space \space \space \space \space \space \space = \sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min(\lfloor \frac{n}{d} \rfloor,\lfloor \frac{m}{d} \rfloor)}\mu(p)p^{2}\times Sum(\lfloor \frac{n}{dp} \rfloor)\times Sum(\lfloor \frac{m}{dp} \rfloor)

其中Sum(x) = \sum_{i=1}^{x}i = \frac{x*(x+1)}{2},等差数列求和,可以O(1)

到这里式子就推完了,前半部分分块,后半部分也分块,时间复杂度 = O(\sqrt{n}) \times O(\sqrt{n}) = O(n)

然后我们重新考虑一个问题

如果我们把这个题目改成有Q组询问,1 \leq Q \leq 5 \times 10^{4}呢?

显然,O(Qn)是过不去的,我们需要对这个式子再做一次反演

我们设 T = d\times p,那我们把T提到前面来,只枚举Tpd可以表示为\frac{T}{p}

ans = \sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min(\lfloor \frac{n}{d} \rfloor,\lfloor \frac{m}{d} \rfloor)}\mu(p)p^{2}\times Sum(\lfloor \frac{n}{dp} \rfloor)\times Sum(\lfloor \frac{m}{dp} \rfloor) \space \space \space \space \space \space \space = \sum_{T=1}^{min(n,m)}Sum(\lfloor \frac{n}{T} \rfloor)\times Sum(\lfloor \frac{m}{T} \rfloor)\sum_{p|T}\mu(p)p^{2}\times \frac{T}{p} \space \space \space \space \space \space \space = \sum_{T=1}^{min(n,m)}Sum(\lfloor \frac{n}{T} \rfloor)\times Sum(\lfloor \frac{m}{T} \rfloor)T\sum_{p|T}\mu(p)p

g(T) = \sum_{p|T}\mu(p)p

我们发现,g是一个积性函数,可以用线性筛筛出来

怎么线筛呢?

对于质数p

inline void GetF(int n) {
    f[1] = 1 , vis[0] = vis[1] = true;
    for(R int i=2; i<=n; i++) {
        if(!vis[i]) f[i] = 1 - i , pri[++tot] = i;
        for(R int j=1; j<=tot&&i*pri[j]<=n; j++) {
            vis[i*pri[j]] = true;
            if(i%pri[j]) f[i*pri[j]] = f[i] * f[pri[j]];
            else    { f[i*pri[j]] = f[i]; break; }
        }
    }
}

这样子整个式子只用分块一次,时间复杂度就是O(\sqrt{n}),可以处理Q组询问了

洛谷P3768 简单的数学题

zzq出的题,快\%\%

题目大意:求\sum_{i=1}^{n}\sum_{j=1}^{m}ijgcd(i,j)的值

对于这道题我们考虑另一种反演方式

我们不用\mu,我们用\varphi

根据\varepsilon = \varphi \times I,我们大力推一波式子:

ans = \sum_{i=1}^{n}\sum_{j=1}^{n}ijgcd(i,j) \space \space \space \space \space \space \space = \sum_{i=1}^{n}\sum_{j=1}^{n}ij\sum_{d|i,j}\varphi(d) \space \space \space \space \space \space \space = \sum_{d=1}^{n}\varphi(d)\sum_{d|i}\sum_{d|j}ij \space \space \space \space \space \space \space = \sum_{d=1}^{n}\varphi(d)\sum_{id=1}^{n}\sum_{jd=1}^{n}idjd \space \space \space \space \space \space \space = \sum_{d=1}^{n}\varphi(d)d^{2}\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}i\sum_{j=1}^{\lfloor \frac{n}{d} \rfloor}j \space \space \space \space \space \space \space = \sum_{d=1}^{n}\varphi(d)d^{2}(\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}i)^{2}

直接大力分块即可

然后看一下数据,wocn \leq 10^{10}GG

这时我们就需要引进一个新的东西,叫做杜教筛

什么是杜教筛?

现在我们就是要求这个东西:\varphi(i)\times i^{2}

挂一下杜教筛的核心公式(全程都要用到他):

g(1)S(n) = \sum_{i=1}^{n}(f\times g)(i) - \sum_{i=2}^{n}g(i)S(\lfloor \frac{n}{i} \rfloor)

我们设f(i) = \varphi(i) \times i^{2}g(i) = i^{2}

(f\times g)(i) = \sum_{d|i}f(d)g(\frac{i}{d}) = \sum_{d|i}\varphi(d)d^{2}(\frac{i}{d})^{2} = i^{2}\sum_{d|i}\varphi(d) = i^{3}

带入原式

S(n) = \sum_{i=1}^{n}i^{3} - \sum_{i=2}^{n}i^{2}S(\lfloor \frac{n}{i} \rfloor)

有个非常神奇的公式:

\sum_{i=1}^{n}i^{3} = (\sum_{i=1}^{n}i)^{2}

带入即可:

S(n) = (\sum_{i=1}^{n}i)^{2} - \sum_{i=2}^{n}i^{2}S(\lfloor \frac{n}{i} \rfloor)

这样就可以求解了

inline LL SqrSum(LL x) { x %= Mod; return x * (x+1) % Mod * (x+x+1) % Mod * InvSix % Mod; }

inline LL Phi(LL n) {
    if(n <= Maxn-10)    return f[n];
    if(m.count(n))  return m[n];
    R LL ans = Sqr(Sum(n));
    for(R LL i=2,j; i<=n; i=j+1) {
        j = n / ( n / i );
        ans = ( ans - ( SqrSum(j) - SqrSum(i-1) + Mod ) % Mod * Phi(n/i) % Mod + Mod ) % Mod;
    }
    return m[n] = ans;
}