莫比乌斯反演 学习笔记
基本定义
数论函数:定义域为正整数的函数。
积性函数:满足 \(\forall n,m\in \mathbb{N}^+,\gcd(x,y)=1,f(x)f(y)=f(xy)\) 的函数 \(f\)。
完全积性函数:满足 \(\forall n,m\in \mathbb{N}^+,f(x)f(y)=f(xy)\) 的函数 \(f\)。
重要积性函数:
-
单位函数 \(\varepsilon(n)=[n=1]\)。
-
幂函数 \(\operatorname{Id}_k(n)=n^k\)。特化:当 \(k=1\) 时为恒等函数 \(\operatorname{Id}(n)=n\),当 \(k=0\) 时为 \(1\) 函数 \(\mathbf{1}(n)=1\)。
-
除数函数 \(\sigma_k(n)=\sum_{d\mid n}d^k\)。特化:当 \(k=1\) 时为因数和函数 \(\sigma(n)\),当 \(k=0\) 时为因数个数函数,又记作 \(d(n)\)。
-
欧拉函数 \(\varphi(n)=\sum_{i=1}^n[\gcd(i,n)=1]\)。
-
莫比乌斯函数 \(\mu(n)=\begin{cases}1\,&n=1\\0\,&\exists d>1,d^2\mid n\\(-1)^{\omega(n)}\,&\text{otherwise}\end{cases}\)。其中 \(\omega(n)\) 表示 \(n\) 的本质不同质因子个数。
其中前三个为完全积性函数。
狄利克雷卷积
狄利克雷卷积是数论函数之间的二元运算,记作 \((f\ast g)(n)=\sum_{d\mid n}f(d)g(\frac n d)\)。也可表示为 \((f\ast g)(n)=\sum_{xy=n}f(x)g(y)\)。
性质:
- 交换律 \(f\ast g=g\ast f\)。
交换 \(x,y\) 即证。
- 结合律 \((f\ast g)\ast h=f\ast(g\ast h)\)。
同理,\((f\ast(g\ast h))(n)=\sum_{xy=n}(\sum_{uv=x}f(u)g(v))h(y)=\sum_{uvw=n}f(u)g(v)h(w)\)。
- 分配律 \((f+g)\ast h=f\ast h+g\ast h\)。
- \(\varepsilon\) 是狄利克雷卷积的单位元。
- 两个积性函数的狄利克雷卷积也是积性函数。
设 \(\gcd(a,b)=1\),\((f\ast g)(a)\cdot (f\ast g)(b)=\sum_{d_1\mid a}f(d_1)g(\frac a{d_1})\cdot\sum_{d_2\mid b}f(d_2)g(\frac b{d_2})=\sum_{d_1\mid a,d2\mid b}f(d_1)f(d_2)g(\frac a{d_1})g(\frac b{d_2})\)。
由于 \(f,g\) 为积性函数且 \(a,b\) 互质,原式等于 \(\sum_{d_1\mid a,d2\mid b}f(d_1d_2)g(\frac{ab}{d_1d_2})=\sum_{d\mid ab}f(d)g(\frac{ab}{d})=(f\ast g)(ab)\)。
- 若 \(f\ast g=\varepsilon\),则 \(g\) 为 \(f\) 的狄利克雷逆元,记作 \(f^{-1}\)。积性函数的狄利克雷逆元也是积性函数。
首先构造 \(g\)。
这也可以看出当 \(f(1)=0\) 时不存在逆元。
由积性函数定义可知 \(f(1)=1\)。数学归纳法。当 \(ab=1\),显然成立。
当 \(ab>1,\gcd(a,b)=1\),设 \(\forall \gcd(x,y)=1,xy<nm,g(xy)=g(x)g(y)\)。
莫比乌斯反演
通过狄利克雷卷积的性质可得一些推论。
- \(\mu=\mathbf{1}^{-1}\)。
有 \(\mu(1)=0,\mu(p)=-1(p\in\mathbb{P})\)。那么 \(p(p^2)=\varepsilon(n)-\mu(1)-\mu(p)=0\)。同理 \(\mu(p^k)=0(p\in\mathbb{P},k>1)\),由于 \(\mu\) 是积性函数,可以乘出 \(\mu\) 的表达式。
那么 \((\mu\ast\mathbf{1})(n)=\sum_{d\mid n}\mu(d)=\varepsilon(n)=[n=1]\)。
重要结论:\([\gcd(i,j)=1]=\sum_{d\mid i,d\mid j}\mu(d)\),在化带 \(\gcd\) 的式子时很有用。
这相当于 \(f(n)=\sum_{d\mid n}g(d)\),则 \(g(n)=\sum_{d\mid n}f(d)\mu(\frac n d)\)。
换一个角度理解:使用容斥原理。当 \(n\) 的质因数的次数都为一,这相当于用 \(\frac nd\) 的质因子数大于等于 \(0\) 的,减去大于等于 \(1\) 的,加上大于等于 \(2\) 的,以此类推。此时容斥系数为 \((-1)^{\omega(\frac nd)}\)。发现此时有平方因子数已经计算过,则 \(\mu(n)=\begin{cases}1\,&n=1\\0\,&\exists d>1,d^2\mid n\\(-1)^{\omega(n)}\,&\text{otherwise}\end{cases}\)
- \(\operatorname{Id}_k\ast\mathbf{1}=\sigma_k\)。
由定义可证。
- 若 \(f(n)=\sum_{d\mid n}g(d)\),则 \(g(n)=\sum_{d\mid n}\mu(d)f(\frac n d)\)。
即 \(f\ast\mathbf{1}=g\Leftrightarrow f=g\ast\mu\)。
- \(\varphi\ast\mathbf{1}=\operatorname{Id}\),即 \(\sum_{d\mid n}\varphi(d)=n\)。
当 \(n=p^k(p\in\mathbb{P})\),\(\sum_{d\mid n}\varphi(d)=\varphi(1)+\sum_{i=1}^k(p^i-p^{i-1})=p^k=n\)。而任何数都可以被分解为 \(\prod p_i^{k_i}\) 的形式,这个函数又是积性函数,乘出来为 \(n\)。
另外有 \(\varphi(n)=\sum_{d\mid n}d\mu(\frac n d)\),也就是 \(\varphi=\operatorname{Id}\ast\mu\)。
- 若 \(f(n)=\sum_{n\mid d}g(d)\),则 \(g(n)=\sum_{n\mid d}\mu(\frac d n)f(d)\)。
贝尔级数
对于积性函数,可以把函数值拆成若干个质数的幂。当两个积性函数在质数的幂处的取值相同时,这两个函数相同。
将质数的幂处的取值单独拿出来。发现此时狄利克雷卷积类似于加法卷积,只需要把幂次看做质数的下标。
定义数论函数 \(f\) 在模质数 \(p\) 意义下的贝尔级数 \(f_p(x)=\sum_{i=0}^{\infty}f(p^i)x^i\),两个函数的狄利克雷卷积的贝尔级数等于这两个函数的贝尔级数相乘。类似生成函数,可以将贝尔级数化为封闭形式。
这也可以得出 \(\mu\ast\mathbf{1}=\varepsilon,\varphi\ast\mathbf{1}=\operatorname{Id}\)。
利用贝尔级数可以方便的构造卷积,比如杜教筛。
狄利克雷前缀和
在莫反中,常常需要求一个函数卷上 \(1\) 或者 \(\mu\)。
比如给出一个数组 \(a\),求另一个数组 \(b\),\(b_i=\sum_{j\mid i}a_j\)。实际上就是求任意数论函数与 \(\mathbf{1}\) 的狄利克雷卷积。
用高维前缀和理解。把每个质因数看做一维,新下标就是原下标的质因子的次数。那么狄利克雷前缀和就是在这个数组上做高维前缀和。
for(int i=1;i<=cnt;i++)for(int j=1;prime[i]*j<=n;j++)a[prime[i]*j]+=a[j];
假如枚举倍数,即 \(b_i=\sum_{i\mid j}a_j\),那么做后缀和即可。
for(int i=1;i<=cnt;i++)for(int j=n/prime[i];j>=1;j--)a[j]+=a[prime[i]*j];
如果从 \(b\) 倒推回 \(a\),只需要按相反的方向减回去。
for(int i=cnt;i>=1;i--)for(int j=n/prime[i];j>=1;j--)a[prime[i]*j]-=a[j];
for(int i=cnt;i>=1;i--)for(int j=1;j*prime[i]<=n;j++)a[j]-=a[prime[i]*j];
其中逆狄利克雷前缀和也可以看做卷 \(\mu\)。
复杂度同埃氏筛,\(O(n\log\log n)\)。
gcd 卷积
狄利克雷卷积的一个比较妙的应用。给定长 \(n\) 的序列 \(f,g\),求 \(h_k=\sum_{\gcd(i,j)=k}f_ig_j\)。
考虑构造一种变换,将卷积变成点乘。构造 \(f'_i=\sum_{i\mid d}f_d,g'_i=\sum_{i\mid d}g_d,h'_i=\sum_{i\mid d}h_d\)。
求出 \(h'\) 后,\(h_i=\sum_{i\mid d}\mu(\frac d i)h‘_i\)。这几步都可以狄利克雷前缀和,\(O(n\log\log n)\)。
例题
直接莫反:
这说明莫反有一个经典套路:枚举 \(\gcd\) 出现形如 \([\gcd(i,j)=1]\) 的东西,反演后把求和号提前。
更为直接的方式是运用性质 \(\varphi\ast\mathbf{1}=\operatorname{Id}\)。
#include<bits/stdc++.h>
using namespace std;
int phi_init(int n,int prime[],int phi[],bool a[],int cnt=0){
phi[1]=1;
for(int i=2;i<=n;i++)a[i]=1;
for(int i=2;i<=n;i++){
if(a[i])prime[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
a[i*prime[j]]=0;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
return cnt;
}
int n,prime[100005],phi[100005];
long long ans;
bool a[100005];
int main(){
cin>>n,phi_init(n,prime,phi,a);
for(int i=1;i<=n;i++)phi[i]+=phi[i-1];
for(int l=1,r;l<=n;l=r+1)r=n/(n/l),ans+=1ll*(phi[r]-phi[l-1])*(n/l)*(n/l);
return cout<<ans<<'\n',0;
}
如果要整除分块,需要知道 \(f(x)=\sum_{d\in\mathbb{P},d\mid x}\mu(\frac x p)\) 的前缀和。考虑筛法。设 \(x\) 是由 \(ij\) 筛出来的,\(j\) 为 \(x\) 的最小质因子。
当 \(x\in\mathbb{P}\):\(f(x)=\mu(1)=1\)。
当 \(j\mid i\),\(f(x)\) 比 \(f(i)\) 多的部分中 \(d\) 应该比 \(i\) 多一个质因子 \(j\) ,而 \(j\) 的次数大于一,不产生贡献。即 \(f(x)=f(i)\)。
当 \(j\nmid i\),\(f(x)\) 比 \(f(i)\) 的多的部分为 \(\mu(i)\),而剩余部分之和根据 \(\mu\) 的定义为 \(f(i)\) 取反。即 \(f(x)=-f(i)+\mu(i)\)。
#include<bits/stdc++.h>
using namespace std;
int t,n,m,prime[10000005],mu[10000005],sum[10000005];
bool a[10000005];
int mu_init(int n,int prime[],int mu[],int sum[],bool a[],int cnt=0){
mu[1]=1;
for(int i=2;i<=n;i++)a[i]=1;
for(int i=2;i<=n;i++){
if(a[i])prime[++cnt]=i,mu[i]=-1,sum[i]=1;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
a[i*prime[j]]=0;
if(i%prime[j]==0){
mu[i*prime[j]]=0,sum[i*prime[j]]=mu[i];
break;
}
else mu[i*prime[j]]=-mu[i],sum[i*prime[j]]=-sum[i]+mu[i];
}
}
return cnt;
}
long long calc(int n,int m,long long ans=0){
for(int l=1,r;l<=min(n,m);l=r+1)r=min(n/(n/l),m/(m/l)),ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
return ans;
}
int main(){
mu_init(10000000,prime,mu,sum,a);
for(int i=1;i<=10000000;i++)sum[i]+=sum[i-1];
cin>>t;
while(t--)cin>>n>>m,cout<<calc(n,m)<<'\n';
return 0;
}
其中有一个重要结论 \(d(ij)=\sum_{x\mid i}\sum_{y\mid j}[\gcd(x,y)=1]\)。枚举因数在 \(i,j\) 的两部分,但这样会造成重复。对于每个因数拆成 \(x,y\) 时,只保留 \(x\) 的因数最多的一种拆分,即第二行。由于 \(x,\frac i x\) 成对,这等价于第三行。
整除分块时需要求 \(\sum_{i=1}^{\lfloor\frac n d\rfloor}\lfloor\frac n{id}\rfloor\),可以跑 \(n\) 次整除分块预处理 \(f(n)=\sum_{i=1}^n\lfloor\frac n i\rfloor\)。
还有一种更优的方法:
所以 \(f\) 就是 \(d\) 的前缀和,线性筛即可 \(O(n)\) 预处理。
#include<bits/stdc++.h>
using namespace std;
int t,n,m,prime[50005],mu[50005],d[50005],num[50005];
bool a[50005];
int prime_init(int n,int prime[],int mu[],int d[],bool a[],int cnt=0){
mu[1]=d[1]=1;
for(int i=2;i<=n;i++)a[i]=1;
for(int i=2;i<=n;i++){
if(a[i])prime[++cnt]=i,mu[i]=-1,num[i]=1,d[i]=2;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
a[i*prime[j]]=0;
if(i%prime[j]==0){
mu[i*prime[j]]=0,num[i*prime[j]]=num[i]+1,d[i*prime[j]]=d[i]/(num[i]+1)*(num[i*prime[j]]+1);
break;
}
else mu[i*prime[j]]=-mu[i],num[i*prime[j]]=1,d[i*prime[j]]=d[i]*d[prime[j]];
}
}
return cnt;
}
long long calc(int n,int m,long long ans=0){
for(int l=1,r;l<=min(n,m);l=r+1)r=min(n/(n/l),m/(m/l)),ans+=1ll*(mu[r]-mu[l-1])*d[n/l]*d[m/l];
return ans;
}
int main(){
prime_init(50000,prime,mu,d,a);
for(int i=1;i<=50000;i++)mu[i]+=mu[i-1],d[i]+=d[i-1];
cin>>t;
while(t--)cin>>n>>m,cout<<calc(n,m)<<'\n';
return 0;
}
观察后面的部分。
所以 \(f(n)\) 是积性函数。原式等于 \(n\sum_{d\mid n}f(\frac n d)=n(\mathbf{1}\ast f)(n)\)。因此原式也是积性的,可以线性筛。
#include<bits/stdc++.h>
using namespace std;
char buf1[2097152],*ip1=buf1,*ip2=buf1;
inline int getc(){
return ip1==ip2&&(ip2=(ip1=buf1)+fread(buf1,1,2097152,stdin),ip1==ip2)?EOF:*ip1++;
}
template<typename T>void in(T &a)
{
T ans=0;
char c=getc();
for(;c<'0'||c>'9';c=getc());
for(;c>='0'&&c<='9';c=getc())ans=ans*10+c-'0';
a=ans;
}
template<typename T,typename... Args>void in(T &a,Args&...args)
{
in(a),in(args...);
}
int t,n,prime[1000005],low[1000005];
long long f[1000005];
bool a[1000005];
int f_init(int n,int prime[],int low[],long long f[],bool a[],int cnt=0){
f[1]=1;
for(int i=2;i<=n;i++)a[i]=1;
for(int i=2;i<=n;i++){
if(a[i])prime[++cnt]=i,low[i]=i,f[i]=1ll*(i-1)*i+1;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
a[i*prime[j]]=0;
if(i%prime[j]==0){
low[i*prime[j]]=low[i]*low[prime[j]];
if(i==low[i])f[i*prime[j]]=f[i]+1ll*low[i]*low[i]*(prime[j]-1)*prime[j];
else f[i*prime[j]]=f[i/low[i]]*f[low[i]*prime[j]];
break;
}
else low[i*prime[j]]=prime[j],f[i*prime[j]]=f[i]*f[prime[j]];
}
}
return cnt;
}
int main(){
f_init(1000000,prime,low,f,a),in(t);
while(t--)in(n),cout<<(f[n]+1)*n/2<<'\n';
return 0;
}
其中 \(\prod_{d\mid T}f_d^{\mu(\frac T d)}\) 带一个斐波那契,不好线性筛。但是可以枚举 \(d\) 对每个 \(T\) 的贡献,调和级数 \(O(n\ln n)\) 枚举。预处理 \(f\) 的前缀积和前缀积的逆元即可整除分块。
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int t,n,m,prime[1000005],mu[1000005],f[1000005],g[1000005],invg[1000005];
bool a[1000005];
template<typename T>T qpow(T a,T b,T n,T ans=1){
for(a%=n;b;b>>=1)b&1&&(ans=1ll*ans*a%n),a=1ll*a*a%n;
return ans;
}
template<typename T>T inv(T a,T b)
{
return qpow(a,b-2,b);
}
int prime_init(int n,int prime[],int mu[],int f[],int g[],int invg[],bool a[],int cnt=0){
mu[1]=f[1]=g[0]=invg[0]=g[1]=1;
for(int i=2;i<=n;i++)a[i]=1,f[i]=g[i]=(f[i-1]+f[i-2])%mod;
for(int i=2;i<=n;i++){
if(a[i])prime[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
a[i*prime[j]]=0;
if(i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=2;i<=n;i++){
int t=inv(f[i],mod);
for(int j=2;i*j<=n;j++){
if(mu[j]==1)g[i*j]=1ll*g[i*j]*f[i]%mod;
else if(mu[j]==-1)g[i*j]=1ll*g[i*j]*t%mod;
}
}
for(int i=1;i<=n;i++)g[i]=1ll*g[i]*g[i-1]%mod,invg[i]=inv(g[i],mod);
return cnt;
}
int calc(int n,int m,int ans=1){
for(int l=1,r;l<=min(n,m);l=r+1)r=min(n/(n/l),m/(m/l)),ans=1ll*ans*qpow(1ll*g[r]*invg[l-1]%mod,1ll*(n/l)*(m/l)%(mod-1),1ll*mod)%mod;
return ans;
}
int main(){
prime_init(1000000,prime,mu,f,g,invg,a),cin>>t;
while(t--)cin>>n>>m,cout<<calc(n,m)<<'\n';
return 0;
}
[[数学]]

浙公网安备 33010602011771号