线性筛

在这里提供三种线性筛的讲解,它们分别是:素数筛,欧拉筛和莫比乌斯筛。

筛法正确性的重要理论依据:
上述函数均为积性函数。积性函数的性质为:若f(x)是一个积性函数,那么对于任意素数a,b,满足f(ab)=f(a)*f(b)

一些可爱的要点(有助于理解筛法原理):

1.欧拉筛和莫比乌斯筛是以素数筛为基础的。

2.三者在代码实现上几乎是同一框架。

3.欧拉函数和莫比乌斯函数的定义介绍:

(1)欧拉函数Phi(x)表示小于等于x的正整数中和x互质的数的个数(注意,1与任何数互质)。

(2)莫比乌斯函数Mob(x)仅有三种值:0,-1,1————如果x能够被一个大于0的整数的平方整除,那么函数值为0;如果x拥有奇数种 质因数,那么函数值为-1,有偶数种质因数,那么函数值为1(莫比乌斯函数的神奇定义决定了它应用于容斥问题......)。

线性筛的两大步骤:

(1)获得范围内的素数

线性筛的线性体现在尽可能的使每个数只被“筛”一次。其思想众所周知地基于: a为任何数,b为质数,那么a*b就不是质数。

在程序实现中体现为,对于当前枚举的数i,使用所有小于等于i的素数p,去“筛除”数(p * i),即将布尔数组对应位置设为1(表示不为素数)。

值得注意的是,这里会出现三个筛法都会 涉及的关键语句:“if(i%Prime[j]==0)break;”。这是一个很简单有效的优化,原理依旧是基于“尽量只筛一次”。

下面对这个优化做出解释:在这里我们提出“最小质因子”的概念,然后我们规定每个合数都只被它的最小质因子筛出————这个定义很好地契合了“尽可能只筛一次”的想法。

回到问题,当前如果出现"i%Prime[j]==0"的情况,由于枚举素数Prime[j]是从小到大的,那么可以说明Prime[j]是i的最小质因子。

此时如果不终止循环,那么Prime[j+1],Prime[j+2]...会与i相乘得到结果然后筛掉这个结果,但是我们从式子中看出,得到的结果的最小质因子是Prime[j],然而我们使用了j之后的素数筛掉了它,不符合开始的原则,这样做 会使得一个数被筛多次,降低了效率。举例说明则是:20应该由2 * 10筛掉,而不是被4 * 5筛掉(素数2<素数5)。

然后这里就给出素数筛代码吧吧吧:

素数的线性筛

欧拉筛算法步骤:

1.如果上界小于2,没有素数,返回。

2.标记i=2为第一个素数。然后如果没有到达上界,转移到步骤3,否则转移到步骤5。

  1. 令i自增1。检验i是否是素数,如果是素数,将其填入素数数组中,转移到步骤4。

4.,无论它是不是素数,都将它与目前已经找到的素数的乘积判定为合数。如果某一个素数可以被当前这个数 i 整除,或者所有已经选出的素数都已经遍历过,或者当前素数*i后大于上界,转移到步骤5。

5.到上界后,返回。否则转移到步骤3。

(二)莫比乌斯函数的线性筛

首先给出欧拉函数的定义式子:

我们在这里使用和上文筛欧拉函数类似的分类讨论: (设p为素数)

1.μ(p)=-1 ②已知μ(x),且p能够整除x,则μ(x*p)=0

2.已知μ(x),且p不能够整除x,则μ(x*p)=-μ(x)

三个结论的证明比上文的Euler要简单很多——只需要照着莫比乌斯函数的定义去讨论0,1,-1三种情况就是了。

posted @ 2020-10-04 20:02  panjoel  阅读(306)  评论(0)    收藏  举报