【学习笔记】莫比乌斯反演

前言/声明

首先,本人的数论水平极低,目前莫反只是刚刚入门的水平,此博客的主要作用是用于记录本人的学习过程,真的想要深入了解莫反的话这边推荐 cmd 大佬的博客(点这里),应该对你有更大帮助。

建议学习的时候能多理解些就多去理解,少硬记些结论,这样更不容易忘记。

前置知识:最基础的数论。

0 基本定义与符号

  • 整除:对于任意两个整数 a,b,如果有 amodb=0,则称 b 整除 a,记作 ba
  • 最大公约数:对于任意两个整数 a,b,称 da,b 的最大公约数当且仅当 d 是能整除 a,b 的最大整数,记作 gcd(a,b),或简记为 (a,b)
  • 艾弗森括号:[???] 表示的是,如果中括号内的东西为真,则值为 1,否则为 0。比如:[1.14>0.514]=1, [2<9]=0
  • 欧拉函数:对于正整数 n,欧拉函数表示 [1,n] 内与 n 互质的正整数的个数,记作 φ(n)

1 数论函数与狄利克雷卷积

1.1 数论函数

定义:定义域为正整数(陪域为复数)的函数。

如果下文中没有特殊说明,所有提到的函数都是数论函数,所有提到的数也均为整数

1.1.1 积性函数#

定义:如果数论函数 f 满足对于任意两个互质的正整数 a,b 都有 f(a)f(b)=f(ab),则称 f 是一个积性函数

就比如大家应该很熟悉的欧拉函数 φ,以及下文会提到的莫比乌斯函数 μ,都属于积性函数。

1.1.2 完全积性函数#

定义:如果数论函数 f 满足对于任意两个正整数 a,b没有任何其他限制,都有 f(a)f(b)=f(ab),则称 f 是一个完全积性函数

下面,为大家介绍几个下文会经常用到的完全积性函数:

  • 恒等函数 I,对于所有正整数 n,都有 I(n)=1经常作为废话出现
  • 元函数 e,对于所有正整数 ne(n)=[n=1],即当且仅当 n=1 时值为 1,否则为 0,是狄利克雷卷积的单位元(下文会提到)。
  • 单位函数 id,对于所有正整数 nid(n)=n
  • 幂函数 idx,对于所有正整数 nidx(n)=nx单位函数是幂函数的特殊情况

显然,完全积性函数 积性函数。

1.2 狄利克雷卷积

定义:设 fg 是两个数论函数,则它们的狄利克雷卷积是一个新的数论函数,记作 fg,规则如下:

fg(n)=dnf(d)g(nd)

可以理解为对数论函数定义的一种运算

比如,fg(8)=f(1)g(8)+f(2)g(4)+f(4)g(2)+f(8)g(1)

狄利克雷卷积满足以下运算律:

  • 交换律:fg=gh
  • 结合律:fgh=f(gh)
  • 分配律:f(g+h)=fg+fh,这里数论函数的加法定义为点值相加,即 (f+g)(n)=f(n)+g(n)

比较显然,直接把式子套上去就能证明,具体过程这里不再给出。

对于任意数论函数 f,总是有 fe=f,因此 e狄利克雷卷积的单位元

证明:fe(n)=dnf(d)e(nd),显然当且仅当 nd=1,即 d=nf(d) 对结果才会有贡献。

对于任意数论函数 fg,如果 fg=e,则称 gf 在狄利克雷卷积意义下的,也记作 f1

1.3 相关性质

  • 对于一个积性函数 f,一定有 f(1)=1

    证明:由积性函数定义,得 f(1)=f(1)f(1),所以 f(1)=1

  • 对于一个积性函数 ff(n)=f(p1e1)f(p2e2)...f(pmem),其中 p1,p2,...pme1,e2,...,em 分别对应 n 质因数分解后的每个质因子及其对应次数。

    证明:p1e1,p2e2,...,pmem 显然互质,由积性函数定义可得上式。

  • 两个积性函数的狄利克雷卷积仍是积性函数。

    证明:设 f,g 是两个积性函数,a,b 是两个互质的正整数,它们的狄利克雷卷积为 h

    h(a)h(b)=daf(d)g(ad)tbf(t)g(bt)=datbf(d)f(t)g(ad)g(bt)

    考虑合并求和符号,改为枚举 dt 右边的部分显然可以根据积性函数性质合并:

    =dtabf(dt)g(abdt)=h(ab)

    原命题得证。

2 莫比乌斯函数

了解了上面的前置知识之后,我们就可以逐步引出主角莫比乌斯函数了。

2.1 来源

假设现在有两个单变量函数 Ff,它们之间满足如下关系:

F(n)=dnf(d)

如果 f 函数的值易求,那么我们显然根据上式就可以算出 F 的值了。

不过现在又有一个新的问题,如果易求的函数是 F,那么我们该如何求出 f 的值呢?

我们考虑将上面的式子变为狄利克雷卷积的形式:

F(n)=dnI(d)f(d)F=If

两边同时乘上 I 的逆,即 I1,可得:

f=FI1

那么如果我们能够求出 I1 是什么,f 也就能够求出来了。

而这个 I1,就是我们的莫比乌斯函数 μ

但是新的问题又来了,μ 函数的值到底是什么呢?

2.2 定义

首先,μ 是一个积性函数,因为积性函数的逆还是积性函数。

而一个积性函数的逆其实是可以构造出来的,具体构造的方法:点这里查看

因为比较复杂(其实是我不会),具体过程这里不再具体给出。

莫比乌斯函数的定义如下:

  • n=1,则 μ(n)=1
  • n=p1p2...pkpi 是互不相同的质数,那么 μ(n)=(1)k
  • 否则 μ(n)=0

显然,μ 的取值只有 1,0,1 三种,这决定了其本质其实为容斥系数

2.3 相关性质

  • 对于任意的正整数 n,总是有:

    e(n)=dnμ(d)

    显然,因为 μ=I1,而上式等价于 e=μI。下面给出具体证明过程:

    • n=1 时显然成立。

    • n1 时,对 n 进行质因子分解得 n=p1e1p2e2...pkek。在 n 的所有因子当中,当且仅当其所有质因子次数都是 1μ 值才不为 0,而含有 r 个不同质因子的因子有 Ckr 个,那么显然有:

      dnμ(d)=Ck0Ck1+Ck2+...+(1)kCkk=i=0k(1)iCki

      根据二项式定理 i=0kCkixiyni=(x+y)k,令 x=1,y=1,代入可得原式为 0

  • 对于任意的正整数 n,总是有:

    φ(n)=dnμ(d)nd

    上式等价于 φ=μid,证明涉及较复杂的容斥,不具体展开。

2.4 程序求解

  • 质因数分解暴力求解,直接根据定义即可,单次复杂度 O(n)

  • 根据积性函数性质,线性筛预处理,总复杂度 O(n)

    Copy
    void init(int n){ memset(isPrime,1,sizeof(isPrime)); isPrime[1]=0;mu[1]=1; For(i,2,n){ if(isPrime[i]) pri[++cnt]=i,mu[i]=-1; For(j,1,cnt){ if(i*pri[j]>n) break; isPrime[i*pri[j]]=0; mu[i*pri[j]]=(i%pri[j]==0)?0:-mu[i]; if(i%pri[j]==0) break; } } }

3 莫比乌斯反演公式

  • 公式一:

    [n=m]=[n|m]d(n/m)μ(d)

    证明:显然 [n=m][nm][n/m=1],由 e=μI,用 e(n/m) 替换掉 [n/m=1] 可得上式。

  • 公式二:

    F(n)=dnf(d)f(n)=dnμ(d)F(nd)

    证明:见上文 2.1 部分,不再重复。

  • 公式三:

    F(n)=ndf(d)f(n)=ndμ(dn)F(d)

    限于本人水平,不证。

4 例题

目前准备了三四道,但都是十分基础的那种入门题,有空立马来写。。。

4.1 公式一的应用

公式一是最好掌握,但也是最需要掌握的内容,下面我们来几道题实战一下。

【例题一】互质数对#

题目大意Q 次询问,每次给定 n,m,求

i=1nj=1m[(i,j)=1]

其中 1n,m,Q105mn

题目分析:考虑用公式一来替换 [(i,j)=1],变成求解:

i=1nj=1md(i,j)μ(d)

考虑一个经典结论:d(i,j)didj,此时变为求解:

i=1nj=1mdidjμ(d)

再接下来,我们再使用一个经典套路——交换枚举顺序,观察交换后的新限制

考虑如果我们先枚举 d,那么此时就变为了给 ij 分别添加了 didj 的限制,变成了:

d=1nμ(d)didj1

考虑 didj1 这项如何处理,其实就相当于是 n 以内 d 的倍数的数量和 m 以内 d 的倍数的数量之积,显然前者其实就是 nd,后者其实就是 md,那么现在就变成了:

d=1nμ(d)ndmd

如果我们用线性筛预处理 μ,现在单次询问的复杂度已经降到了 O(n),但对于题目中的数据范围还是无法通过。

但是很显然 后面的那些可以使用预处理 μ 前缀和+整除分块的方法,这样我们单次询问的复杂度可以做到 O(n),总时间复杂度降为 O(n+Tn),问题解决。

如果你不会整除分块,点这里

Copy
int T,n,m,cnt,pri[N],mu[N],sm[N]; bool isPrime[N]; void init(int n){ //预处理 mu memset(isPrime,1,sizeof(isPrime)); isPrime[1]=0;mu[1]=-1; For(i,2,n){ if(isPrime[i]) pri[++cnt]=i,mu[i]=1; For(j,1,cnt){ if(i*pri[j]>n) break; isPrime[i*pri[j]]=0; mu[i*pri[j]]=(i%pri[j]==0)?0:-mu[i]; if(i%pri[j]==0) break; } } For(i,1,n) sm[i]=sm[i-1]+mu[i]; //对 mu 前缀和 } ll calc(int n,int m){ //整除分块 ll ans=0; for(int l=1,r=0;l<=min(n,m);l=r+1){ r=min(n/(n/l),m/(m/l)); ans+=1ll*(n/l)*(m/l)*(sm[r]-sm[l-1]); //计算答案 } return ans; } void Main(){ init(1e5);read(T); while(T--){ read(n,m); printf("%lld\n",calc(n,m)); } }

【例题二】gcd 求和#

题目大意:给定你 n,试求:

i=1nj=1n(i,j)

其中 n2×106这意味着 O(nn) 的复杂度将无法通过

题目分析:我们可以试着继续整出来上题中那种 [(i,j)=1] 的形式,方便我们求解。

首先,我们考虑去枚举 gcd 的结果 d,变成如下形式:

d=1ndi=1nj=1n[(i,j)=d]

经典结论:(i,j)=d(i/d,j/d)=1,套用到上式:

d=1ndi=1ndj=1nd[(i,j)=1]

考虑故技重施,再用上一题的方法进行变形:

d=1ndi=1ndj=1nd[(i,j)=1]d=1ndi=1ndj=1ndk(i,j)μ(k)d=1ndi=1ndj=1ndkikjμ(k)d=1ndk=1nμ(k)(ndk)2

分析下此时的复杂度,后面那个 可以预处理前缀和+除法分块,已经快了很多了,但仍为 O(nn)

蛇皮操作之——改变枚举量,令 T=dk,先枚举 T,然后再变成:

T=1ndTdμ(Td)(nT)2

μid=φ,发现还可以继续化为:

T=1nφ(T)(nT)2

显然可以线性筛出 φ 并求前缀和,然后上个除法分块就行了,这样最后的复杂度为 O(n+n)

Copy
ll n,cnt,pri[N],phi[N],s[N]; bool isPrime[N]; void init(int n){ memset(isPrime,1,sizeof(isPrime)); isPrime[1]=0;phi[1]=1; For(i,2,n){ if(isPrime[i]) pri[++cnt]=i,phi[i]=i-1; for(int j=1;j<=cnt&&i*pri[j]<=n;j++){ isPrime[i*pri[j]]=0; if(!(i%pri[j])){ phi[i*pri[j]]=phi[i]*pri[j]; break; } phi[i*pri[j]]=phi[i]*phi[pri[j]]; } } For(i,1,n) s[i]=s[i-1]+phi[i]; } ll calc(int n){ ll res=0,r; for(int l=1;l<=n;l=r+1){ r=n/(n/l); res+=(s[r]-s[l-1])*(n/l)*(n/l); } return res; } void Main(){ read(n);init(n); printf("%lld",calc(n)); }
posted @   KingPowers  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
CONTENTS