-
前言
本文只是用比较通俗的例子让大家了解一下什么是莫比乌斯反演,其中说明
(明明都是瞎猜)可能有纰漏。本人也是个蒟蒻,未能给出珂学证明,还望多多指教。 -
理论基础
- “|”符号表示整除,
a|b 表示b被a整除,也就是b有a这个因数,b=ka (k∈N)。 - “∑ ”求和符号
- “|”符号表示整除,
-
是什么
请先看这个例子:
假设有两个函数F(n),f(d),且d∈{x| x|n(即n被d整除)}
并有以下关系:F(n)等于所有f(d)之和。比如:6能被1,2,3,6整除,所以F(6)=f(1)+f(2)+f(3)+f(6)
用一个公示表示就是:由此可得到:
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(5)=f(1)+f(5)
F(6)=f(1)+f(2)+f(3)+f(6)
F(7)=f(1)+f(7)
稍微变形得到:
f(1)=F(1)
f(2)=F(2)-f(1)=F(2)-F(1)
f(3)=F(3)-F(1)
f(4)=F(4)-f(2)-f(1)=F(4)-F(2)
f(5)=F(5)-F(1)
f(6)=F(6)-F(3)-F(2)+F(1)
f(7)=F(7)-F(1)
f(8)=F(8)-F(4)
emmmmm这样如果我们知道各个F(n)的值我们肯定能算出各个f(d)的值,只要打表推就可以了,但仔细观察一下,有没有什么规律呢?
好像每一个f(n)都由它所有的因子d∈{x| x|n(即n被d整除)}的F(d)乘上一个0或1或-1的系数再相加得到,我们就把这个系数也看成是d的一个函数μ(d),称作莫比乌斯函数。
那莫比乌斯函数的值我们怎么知道呢?有没有一个通项公式?
我们就从最特殊的f(6)着手:
f(6)=F(6)-F(3)-F(2)+F(1)
我们不妨这样看:f(6)=1×F(6/1)+(-1)×F(6/2)+(-1)×F(6/3)+1×F(6/6)
此时好像有点端倪了,我们可以将F()中每个分母看作d,且把1看做特殊情况:μ(1)=1,易看出μ(2)=-1,μ(3)=-1,μ(6)=1.
这时相信不少大佬已看出μ(d)的值与d本身互异质因子个数有关。
2只有一个质因子2,3只有一个质因子3,而6有两个质因子2和3。假设一正整数d的互异质因子个数为k,则μ(d)=(-1)^k。
特殊的μ(1)=1.那有些μ(d)却等于0怎么解释呢???
比如:f(8)= F(8)-F(4),根据上文的推测,我们知道,f(8)=μ(1)×F(8/1)+μ(2)×F(8/2)+μ(4)×F(8/4)+μ(8)×F(8/8)
再看看上文我们已有的结论,正整数d的互异质因子个数这就要求d必须能为k个互异且互质的数的乘积。但是4=2×2不满足互异,8=2×4不满足互质。
所以我们就猜想除1外不能由几个互质且互异的正整数相乘得到的数d的莫比乌斯函数值为0,例:μ(4)=0,μ(8)=0。
下面总结一下:
-
μ(d)函数是莫比乌斯函数,如果d=1,μ(d)=1
-
如果d为互异质数p1,p2…pk的乘积(若d本身是个质数就看是它本身一个的乘积),则μ(d)=(−1)^k
-
否则,μ(d)=0
然而,我们现在只是会求莫比乌斯函数值,什么是莫比乌斯反演呢?
其实就是下面两个定理:
- 式1(约数关系):若
则
- 式二(倍数关系):若
则
式1在开头已经说过,式2也类似,还请大家拿出草稿纸多演算一下,才能领悟。
-
-
相关
(不会证的)性质好吧我是从百科上截来的,不过我还找到了其他几个(
全都不会证)- 对于大于1的正整数n
- 对于任意正整数n
φ()就是欧拉函数,若不清楚的可以看我的这篇博客:
我又打广告了 -
应用
线性方法求莫比乌斯函数值表
和欧式筛法很像,建议先了解欧式筛法原理,其他详见代码注释
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=19260817;
int n;
int prime[maxn];//记录素数
int mob[maxn];//记录莫比乌斯函数值
bool vis[maxn];
int cnt=0;//记录素数个数
void make_mob(int m)
{
memset(vis,0,sizeof(vis));
mob[1]=1;//特殊
for(int i=2;i<=m;i++)
{
if(!vis[i]){
prime[++cnt]=i;
mob[i]=-1;//素数的μ()为-1,
//只有其本身一个互异互质因子
}
for(int j=1;j<=cnt&&i*prime[j]<=m;j++)
{
vis[i*prime[j]]=1;//筛素数,不必多讲
if(i%prime[j]==0){
mob[i*prime[j]]=0;break;
//设x=i*prime[j]很明显它的两个因子i与prime[j]不互质
//break;大家可以先去看看欧式筛素数原理理解这句话
}
mob[i*prime[j]]=-mob[i];
//不难理解,i*prime[j]比i多了一个因子
}
}
}
int main()
{
cin>>n;
make_mob(n);
for(register int i=1;i<=n;i++)
{
cout<<mob[i]<<' ';
if(i%10==0)putchar('
');
}
return 0;
}