莫比乌斯反演题目技巧与策略笔记

莫比乌斯反演题目技巧与策略笔记

0. 学习目标

莫比乌斯反演不是一个孤立公式,而是一类“从累加量还原精确量”的方法。算法题里通常不会直接告诉你“这里要反演”,而是藏在以下结构里:

  • 从“至少满足某个因子条件”还原到“恰好满足某个值”;
  • 从“约数贡献总和”还原到“单点贡献”;
  • 从“倍数贡献总和”还原到“恰好 gcd 为某个值”;
  • 用 \(\mu\) 把 \([\gcd(i,j)=1]\) 这样的条件拆成可枚举的除法块。

这份笔记重点放在竞赛题中的识别、转化和计算策略。


1. 基础函数与核心恒等式

1.1 莫比乌斯函数 \(\mu(n)\)

\[\mu(n)= \begin{cases} 1,&n=1\\ (-1)^k,&n\text{ 是 }k\text{ 个不同质数的乘积}\\ 0,&n\text{ 含有平方因子} \end{cases} \]

例如:

\[\mu(1)=1,\quad \mu(2)=-1,\quad \mu(6)=1,\quad \mu(12)=0 \]

从容斥角度看,\(\mu(d)\) 就是处理“同时被 \(d\) 的这些质因子整除”时的容斥系数。


1.2 核心恒等式

最重要的是:

\[\sum_{d\mid n}\mu(d)= \begin{cases} 1,&n=1\\ 0,&n>1 \end{cases} \]

也就是:

\[1*\mu=\varepsilon \]

其中:

  • \(1(n)=1\),常数函数;
  • \(\varepsilon(1)=1,\varepsilon(n)=0(n>1)\),卷积单位元。

这个式子可以理解成:除了 \(n=1\) 以外,所有非互质情况都会被容斥抵消掉。


1.3 互质指示函数

由核心恒等式可得:

\[[\gcd(i,j)=1]=\sum_{d\mid \gcd(i,j)}\mu(d) \]

因为令:

\[g=\gcd(i,j) \]

则右边是:

\[\sum_{d\mid g}\mu(d) \]

当 \(g=1\) 时等于 \(1\),当 \(g>1\) 时等于 \(0\)。

这个式子是 gcd 计数题中最常用的拆法。


2. 两类反演形式

2.1 约数和反演

如果:

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

那么:

\[f(n)=\sum_{d\mid n}\mu(d)F\left(\frac{n}{d}\right) \]

也可以写成:

\[f(n)=\sum_{d\mid n}\mu\left(\frac{n}{d}\right)F(d) \]

含义:

\(F(n)\) 是由 \(n\) 的所有约数贡献累加得到的,现在要还原每个 \(f(n)\) 的真实贡献。

典型例子:

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

即:

\[id=\varphi*1 \]

所以:

\[\varphi=id*\mu \]

展开得到:

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


2.2 倍数和反演

如果:

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

在上界为 \(N\) 时,通常写成:

\[F(n)=\sum_{k=1}^{\lfloor N/n\rfloor} f(kn) \]

那么:

\[f(n)=\sum_{k=1}^{\lfloor N/n\rfloor}\mu(k)F(kn) \]

含义:

\(F(n)\) 是所有 \(n\) 的倍数贡献之和,现在要从“被 \(n\) 整除”还原出“恰好等于 \(n\)”。

这是 gcd 计数中最常见的形式。

如果:

\[f(x)=\#\{(i,j):\gcd(i,j)=x\} \]

而:

\[F(x)=\#\{(i,j):x\mid i,\ x\mid j\} \]

那么只要 \(\gcd(i,j)=d\),且 \(x\mid d\),它就会被 \(F(x)\) 统计到,所以:

\[F(x)=\sum_{x\mid d}f(d) \]

这就是倍数和反演。


3. 什么时候想到莫比乌斯反演

3.1 出现 gcd 恰好等于某值

如果题目问:

\[\gcd(i,j)=1 \]

或:

\[\gcd(i,j)=k \]

通常考虑莫比乌斯反演。

常见转化:

\[\gcd(i,j)=k \]

等价于:

\[i=kx,\quad j=ky,\quad \gcd(x,y)=1 \]

然后用:

\[[\gcd(x,y)=1]=\sum_{d\mid x,d\mid y}\mu(d) \]


3.2 “恰好”不好算,“至少”好算

例如:

  • 恰好 \(\gcd=i\) 不好算;
  • 但两个数都能被 \(i\) 整除很好算。

此时令:

\[f(i)=\text{gcd 恰好为 }i\text{ 的方案数} \]

\[F(i)=\text{gcd 是 }i\text{ 的倍数的方案数} \]

那么:

\[F(i)=\sum_{i\mid j} f(j) \]

这是倍数和反演。


3.3 和式中有互质限制

例如:

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

可以拆成:

\[\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d\mid i,d\mid j}\mu(d)a_i b_j \]

交换枚举顺序:

\[\sum_{d=1}^{\min(n,m)}\mu(d) \left(\sum_{d\mid i}a_i\right) \left(\sum_{d\mid j}b_j\right) \]

这类题的关键是:把 \(\gcd=1\) 转成“枚举公共因子 \(d\)”。


3.4 出现 \(\sum\limits_{d\mid n}\) 或 \(\sum\limits_{n\mid d}\)

如果题目结构中出现:

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

考虑约数和反演。

如果出现:

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

考虑倍数和反演。


4. 常用套路总结

套路一:直接拆互质指示函数

题型

求:

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

推导

利用:

\[[\gcd(i,j)=1]=\sum_{d\mid i,d\mid j}\mu(d) \]

所以:

\[ans=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d\mid i,d\mid j}\mu(d) \]

交换枚举顺序:

\[ans=\sum_{d=1}^{\min(n,m)}\mu(d) \left\lfloor\frac{n}{d}\right\rfloor \left\lfloor\frac{m}{d}\right\rfloor \]

结论

\[ans=\sum_{d=1}^{\min(n,m)}\mu(d) \left\lfloor\frac{n}{d}\right\rfloor \left\lfloor\frac{m}{d}\right\rfloor \]

复杂度

如果已经线性筛出 \(\mu\),直接求是 \(O(\min(n,m))\)。

如果需要多组询问,可以预处理 \(\mu\) 前缀和,并用整除分块优化到 \(O(\sqrt{n})\)。


套路二:求 gcd 恰好等于 \(k\)

题型

求:

\[1\le i\le n,\quad 1\le j\le m,\quad \gcd(i,j)=k \]

的数对个数。

推导

令:

\[i=kx,\quad j=ky \]

则:

\[\gcd(i,j)=k \Longleftrightarrow \gcd(x,y)=1 \]

范围变成:

\[1\le x\le \left\lfloor\frac{n}{k}\right\rfloor,\quad 1\le y\le \left\lfloor\frac{m}{k}\right\rfloor \]

所以答案是:

\[\sum_{d=1}^{\min(\lfloor n/k\rfloor,\lfloor m/k\rfloor)} \mu(d) \left\lfloor\frac{n}{kd}\right\rfloor \left\lfloor\frac{m}{kd}\right\rfloor \]


套路三:倍数和反演求 gcd 分布

题型

给定若干个数,求 gcd 恰好为 \(x\) 的非空子集数量。

设数组中有 \(cnt[v]\) 个数等于 \(v\)。

关键定义

令:

\[c_x=\#\{a_i:x\mid a_i\} \]

也就是数组中有多少个数是 \(x\) 的倍数。

那么 gcd 是 \(x\) 的倍数的非空子集数是:

\[F(x)=2^{c_x}-1 \]

令:

\[f(x)=\text{gcd 恰好为 }x\text{ 的非空子集数} \]

因为 gcd 恰好为 \(x,2x,3x,\dots\) 的子集都会被 \(F(x)\) 统计到,所以:

\[F(x)=\sum_{x\mid d}f(d) \]

因此:

\[f(x)=F(x)-\sum_{k\ge 2} f(kx) \]

这是一种从大到小递推的倍数和反演写法。

也可以写成:

\[f(x)=\sum_{k\ge 1}\mu(k)F(kx) \]

实战写法

通常不用显式套 \(\mu\),而是倒序减倍数:

for(int x=V;x>=1;x--){
    f[x]=pow2[c[x]]-1;
    for(int y=x+x;y<=V;y+=x){
        f[x]=(f[x]-f[y]+mod)%mod;
    }
}

这就是倍数和反演的工程写法。


5. 整除分块

很多莫比乌斯题最后会变成:

\[\sum_{d=1}^{n}\mu(d)\left\lfloor\frac{n}{d}\right\rfloor \left\lfloor\frac{m}{d}\right\rfloor \]

如果 \(n,m\) 很大,多组询问不能 \(O(n)\) 求。

注意:

\[\left\lfloor\frac{n}{d}\right\rfloor \]

在一段连续的 \(d\) 上取值不变。

对于当前位置 \(l\),令:

\[a=\left\lfloor\frac{n}{l}\right\rfloor,\quad b=\left\lfloor\frac{m}{l}\right\rfloor \]

那么下一段右端点为:

\[r=\min\left(\left\lfloor\frac{n}{a}\right\rfloor,\left\lfloor\frac{m}{b}\right\rfloor\right) \]

在区间 \([l,r]\) 内:

\[\left\lfloor\frac{n}{d}\right\rfloor=a,\quad \left\lfloor\frac{m}{d}\right\rfloor=b \]

所以:

\[\sum_{d=l}^{r}\mu(d)\left\lfloor\frac nd\right\rfloor \left\lfloor\frac md\right\rfloor = \left(\sum_{d=l}^{r}\mu(d)\right)ab \]

如果预处理:

\[s(n)=\sum_{i=1}^{n}\mu(i) \]

那么区间和是:

\[s(r)-s(l-1) \]

于是单次询问复杂度约为 \(O(\sqrt n)\)。


6. 线性筛求 \(\mu\)

6.1 思路

莫比乌斯函数满足:

  • \(\mu(1)=1\);
  • 如果 \(p\nmid i\),那么 \(\mu(ip)=-\mu(i)\);
  • 如果 \(p\mid i\),那么 \(ip\) 含有平方因子,\(\mu(ip)=0\)。

6.2 代码模板

const int N=10000000+5;
int pri[N],tot,mu[N],vis[N],sumMu[N];

void get_mu(int n){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            pri[++tot]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=tot&&i*pri[j]<=n;j++){
            int p=pri[j];
            vis[i*p]=1;
            if(i%p==0){
                mu[i*p]=0;
                break;
            }else{
                mu[i*p]=-mu[i];
            }
        }
    }
    for(int i=1;i<=n;i++) sumMu[i]=sumMu[i-1]+mu[i];
}

7. 例题一:互质数对数量

题意

给定 \(n,m\),求:

\[1\le i\le n,\quad 1\le j\le m,\quad \gcd(i,j)=1 \]

的有序数对数量。

分析

直接枚举 \(i,j\) 是 \(O(nm)\)。

使用互质指示函数:

\[[\gcd(i,j)=1]=\sum_{d\mid i,d\mid j}\mu(d) \]

所以:

\[ans=\sum_{d=1}^{\min(n,m)}\mu(d) \left\lfloor\frac nd\right\rfloor \left\lfloor\frac md\right\rfloor \]

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'

const int N=1000000+5;
int pri[N],tot,mu[N],vis[N],sumMu[N];

void get_mu(int n){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            pri[++tot]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=tot&&i*pri[j]<=n;j++){
            int p=pri[j];
            vis[i*p]=1;
            if(i%p==0){
                mu[i*p]=0;
                break;
            }else mu[i*p]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++) sumMu[i]=sumMu[i-1]+mu[i];
}

int solve(int n,int m){
    if(n>m) swap(n,m);
    int ans=0;
    for(int l=1,r;l<=n;l=r+1){
        int a=n/l,b=m/l;
        r=min(n/a,m/b);
        ans+=(sumMu[r]-sumMu[l-1])*a*b;
    }
    return ans;
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n,m;
    cin>>n>>m;
    get_mu(min(n,m));
    cout<<solve(n,m)<<endl;
    return 0;
}

重点

这道题体现的是最基础的套路:

\[\gcd=1 \Rightarrow \text{拆互质指示函数} \Rightarrow \text{交换求和} \Rightarrow \text{整除分块} \]


8. 例题二:gcd 等于 \(k\) 的数对数量

题意

给定 \(n,m,k\),求:

\[1\le i\le n,\quad 1\le j\le m,\quad \gcd(i,j)=k \]

的有序数对数量。

分析

令:

\[i=kx,\quad j=ky \]

则:

\[\gcd(i,j)=k\Longleftrightarrow \gcd(x,y)=1 \]

所以问题变成:

\[1\le x\le \left\lfloor\frac nk\right\rfloor,\quad 1\le y\le \left\lfloor\frac mk\right\rfloor,\quad \gcd(x,y)=1 \]

答案就是例题一的形式。

代码

int ans_gcd_k(int n,int m,int k){
    n/=k;
    m/=k;
    if(n<=0||m<=0) return 0;
    return solve(n,m);
}

重点

遇到:

\[\gcd(i,j)=k \]

不要直接反演,先整体除以 \(k\),转成:

\[\gcd(x,y)=1 \]


9. 例题三:求数组中 gcd 为 1 的非空子集数

题意

给定一个长度为 \(n\) 的数组 \(a\),求有多少个非空子集,使得子集中所有数的 gcd 等于 \(1\)。

答案对 \(mod\) 取模。

分析

设最大值为 \(V\)。

令:

\[c_x=\#\{a_i:x\mid a_i\} \]

那么从这些 \(c_x\) 个数中选非空子集,得到的子集 gcd 一定是 \(x\) 的倍数。

所以:

\[F(x)=2^{c_x}-1 \]

表示 gcd 是 \(x\) 的倍数的非空子集数量。

令:

\[f(x)=\text{gcd 恰好为 }x\text{ 的非空子集数量} \]

有:

\[F(x)=\sum_{x\mid d}f(d) \]

倍数和反演:

\[f(x)=F(x)-\sum_{k\ge2}f(kx) \]

答案是:

\[f(1) \]

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'

const int N=1000000+5;
const int mod=1000000007;
int n,a[N],cnt[N],c[N],f[N],pw[N];

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin>>n;
    int V=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        cnt[a[i]]++;
        V=max(V,a[i]);
    }

    pw[0]=1;
    for(int i=1;i<=n;i++) pw[i]=pw[i-1]*2%mod;

    for(int x=1;x<=V;x++){
        for(int y=x;y<=V;y+=x){
            c[x]+=cnt[y];
        }
    }

    for(int x=V;x>=1;x--){
        f[x]=(pw[c[x]]-1+mod)%mod;
        for(int y=x+x;y<=V;y+=x){
            f[x]=(f[x]-f[y]+mod)%mod;
        }
    }

    cout<<f[1]<<endl;
    return 0;
}

重点

这道题的关键不是先想 \(\mu\),而是先定义:

\[F(x)=\text{gcd 是 }x\text{ 的倍数的方案数} \]

因为这个东西非常好算:

\[F(x)=2^{c_x}-1 \]

再通过倍数和反演得到恰好值。


10. 例题四:按 gcd 加权求和

题意

求:

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

分析

把 gcd 的值按 \(d\) 分类:

\[ans=\sum_{d=1}^{\min(n,m)}d\cdot \#\{(i,j):\gcd(i,j)=d\} \]

而:

\[\#\{(i,j):\gcd(i,j)=d\} = \#\{(x,y):1\le x\le n/d,1\le y\le m/d,\gcd(x,y)=1\} \]

所以:

\[ans=\sum_{d=1}^{\min(n,m)}d \sum_{k=1}^{\min(n/d,m/d)} \mu(k) \left\lfloor\frac{n}{dk}\right\rfloor \left\lfloor\frac{m}{dk}\right\rfloor \]

令:

\[t=dk \]

那么可以整理为:

\[ans=\sum_{t=1}^{\min(n,m)} \left\lfloor\frac nt\right\rfloor \left\lfloor\frac mt\right\rfloor \sum_{d\mid t} d\mu\left(\frac td\right) \]

内部:

\[\sum_{d\mid t} d\mu\left(\frac td\right) \]

其实就是:

\[\varphi(t) \]

因为:

\[\varphi=id*\mu \]

所以:

\[ans=\sum_{t=1}^{\min(n,m)} \varphi(t) \left\lfloor\frac nt\right\rfloor \left\lfloor\frac mt\right\rfloor \]

结论

\[\sum_{i=1}^{n}\sum_{j=1}^{m}\gcd(i,j) = \sum_{t=1}^{\min(n,m)} \varphi(t) \left\lfloor\frac nt\right\rfloor \left\lfloor\frac mt\right\rfloor \]

重点

这种题说明:不一定最后都出现 \(\mu\),有时候反演整理以后会变成 \(\varphi\)。


11. 竞赛实战中的解题流程

Step 1:判断是不是 gcd / divisor 结构

看到以下关键词要敏感:

  • \(\gcd(i,j)=1\)
  • \(\gcd(i,j)=k\)
  • \(\gcd\) 加权求和
  • 互质数对
  • 数组子集 gcd
  • 倍数、约数贡献
  • lcm 和 gcd 联合出现

Step 2:区分“恰好”和“至少”

常见对应:

目标 容易统计的量
gcd 恰好为 \(x\) 两个数都被 \(x\) 整除
子集 gcd 恰好为 \(x\) 子集所有数都被 \(x\) 整除
\(\gcd(i,j)=1\) 枚举公共因子 \(d\)
\(\gcd(i,j)=k\) 除以 \(k\),变成互质

Step 3:写出 \(F\) 和 \(f\)

这是最重要的一步。

如果是约数和:

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

如果是倍数和:

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

不要一上来背公式,先把“谁统计了谁”说清楚。


Step 4:选择实现方式

常用实现有三种:

方式一:显式用 \(\mu\)

适合互质数对:

\[ans=\sum_d \mu(d)\left\lfloor\frac nd\right\rfloor\left\lfloor\frac md\right\rfloor \]

方式二:倒序减倍数

适合 gcd 分布、子集 gcd:

for(int x=V;x>=1;x--){
    f[x]=F[x];
    for(int y=x+x;y<=V;y+=x){
        f[x]-=f[y];
    }
}

方式三:整除分块

适合多组大范围询问:

for(int l=1,r;l<=n;l=r+1){
    int a=n/l,b=m/l;
    r=min(n/a,m/b);
    ans+=(sumMu[r]-sumMu[l-1])*a*b;
}

12. 常见坑点

12.1 有序数对和无序数对

\[(i,j) \]

和:

\[(j,i) \]

是否算不同,要看题意。

如果从有序数对转无序数对,不能盲目除以 \(2\),因为 \(i=j\) 的情况要单独处理。


12.2 \(\gcd(i,j)=1\) 中是否包含 \(0\)

很多公式默认:

\[1\le i,j \]

如果范围包含 \(0\),要特别处理:

\[\gcd(0,x)=x \]

例如:

\[\gcd(0,1)=1 \]

但:

\[\gcd(0,x)=1 \]

只有 \(x=1\)。


12.3 上界要取最小值

求:

\[\sum_d \mu(d)\left\lfloor\frac nd\right\rfloor\left\lfloor\frac md\right\rfloor \]

时,\(d\) 只需要枚举到:

\[\min(n,m) \]


12.4 取模时注意负数

倍数减法:

f[x]=(f[x]-f[y]+mod)%mod;

不能直接:

f[x]-=f[y];

除非最后统一处理且不会溢出。


12.5 整除分块右端点

对于:

\[\left\lfloor\frac nl\right\rfloor \]

相同的一段,右端点是:

\[r=\left\lfloor\frac n{\lfloor n/l\rfloor}\right\rfloor \]

如果有两个变量 \(n,m\),则:

\[r=\min\left(\frac n{n/l},\frac m{m/l}\right) \]


13. 总结

莫比乌斯反演题的核心不是背公式,而是识别“累加关系”。

最常用的判断方式:

  1. 如果看到“互质”:

\[[\gcd(i,j)=1]=\sum_{d\mid i,d\mid j}\mu(d) \]

  1. 如果看到“gcd 恰好为 \(x\)”:

\[F(x)=\sum_{x\mid d}f(d) \]

优先考虑倍数和反演。

  1. 如果看到“约数贡献总和”:

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

考虑约数和反演。

  1. 如果答案里有:

\[\left\lfloor\frac nd\right\rfloor \]

并且多组询问,考虑整除分块和 \(\mu\) 前缀和。

一句话概括:

莫比乌斯反演就是用容斥把“被约数或倍数重复统计的贡献”拆回“恰好贡献”。

posted @ 2026-05-20 16:16  艾拉别哭  阅读(39)  评论(0)    收藏  举报