莫比乌斯函数反演
首先我们直接来看莫比乌斯函数 (
μ(d)
).
若d=1则,
μ(d)=1
若d可以分解为k个互不相同的质数的乘积,即
d=p1∗p2∗......∗pk
且
p1<p2<......<pk
那么
μ(d)=(−1)k
除此之外的所有情况,
μ(d)=0
那么问题来了,这个函数有什么用呢?
为了解决这个问题,我们先定义一个函数
那么可以得到
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(n)
呢?
我们可以利用
F(n)
进行计算
f(1)=F(1)
f(2)=F(2)−F(1)
f(3)=F(3)−F(1)
f(4)=F(4)−F(2)
你能直接看出
f(n)
的规律吗?
表示我想了好久都没有找到
显然一般人不可能直接想出来,那么就要用到莫比乌斯反演了。
公式如下
通过莫比乌斯反演我们能够解决这样一种问题。问题的答案 f(n) 比较难求,但是有一个类似 F(n) 的答案非常好求,所以我们可以求到 F(n) 然后通过莫比乌斯反演的得到最终答案。
积性函数
积性函数的定义是若
gcd(x,t)=1
且
f(xy)=f(x)f(y)
,那么则称
f(x)
是一个积性函数。
那么思考一个问题,莫比乌斯函数是积性函数吗?
证明如下:
首先考虑
μ(x)=0
或
μ(y)=0
的情况,则可以得到x或y不能分为若干个不同的素数之积,那么xy也不可以分为若干个不同的素数之积,所以
μ(xy)=0
。
接着是
μ(x)≠0
且
μ(y)≠0
,则x和y可以分为若干个不同的素数之积,又因为x,y互质,所以它们分出的质因子不会用相同,那么xy也可以被分为若干个不同的质数之积。因此可以得到
μ(x)=(−1)k1
μ(y)=(−1)k2
μ(xy)=(−1)k1+k2=μ(x)μ(y)
证明完毕。
所以我们可以通过线性筛法来快速地计算莫比乌斯函数的值。
线性筛法(欧拉筛法)
相对比较朴素的埃拉托斯特尼筛法,欧拉筛法实际上避免了重复筛到一个数字的过程。因为埃氏筛法会让一个数被它每一个大于1的约数筛一遍,所以我们想要以O(n)的时间复杂度完成操作,就必须保证每一个数是被它最小的一个质因子筛去的。
int cnt=0;
bool check[MAXN+5];
memset(check,0,sizeof check);
for(int i=2;i<=MAXN;i++)
{
if(!check[i])
prime[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
if(i*prime[j]>MAXN)
break;
check[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
通过以上的代码我们即可在O(n)的时间复杂度里筛出素数。
与此同时我们可以通过这种方法将莫比乌斯函数算出来。质数的莫比乌斯函数值恒等于-1,其他的情况按照积性函数的定义和莫比乌斯函数值的定义可以轻松得到。
将上述的代码修改即可得到求莫比乌斯函数值的代码。
int cnt=0,miu[MAXN+5];
bool check[MAXN+5];
memset(check,0,sizeof check);
memset(miu,0,sizeof miu);
miu[1]=1;
for(int i=2;i<=MAXN;i++)
{
if(!check[i])
{
prime[++cnt]=i;
miu[i]=-1;
}
for(int j=1;j<=cnt;j++)
{
if(i*prime[j]>MAXN)
break;
check[i*prime[j]]=1;
if(i%prime[j]==0)
{
miu[i*prime[j]]=0;
break;
}
miu[i*prime[j]]=miu[i]*miu[prime[j]];//也可以写成miu[i*prime[j]]=-miu[i];
}
}
以上的内容只是初涉了莫比乌斯函数,并没有包括它的一些性质和证明。其中一些性质可能在之后的习题里提到。