筛法求质数

质数又称素数。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,就叫质数,否则称为合数。

此外特别规定,1既不是质数,也不是合数。

本章的内容将围绕如何快速求出质数展开。

预习篇

1.自然数,整除,因数,约数

先来回忆几个数学概念:

自然数集是全体非负整数组成的集合,表示为 N={0,1,2,3,...}

整除是两个自然数之间的一种关系。

自然数a可以被自然数b整除,是a除以b没有余数。此时ba因数或称约数ab的整数倍数。

2. 质数和朴素试除法

质数是指只能被1和其自身整除的数。

判断一个数x是否是质数(很多时候称为素性测试),最简单的方法是试除法。试除,就是用2,3,...,x1这些数字尝试整除x。只要其中有一个数能整除x,就说明x是合数,反之是质数。

程序的过程,就像在数轴x1的位置建了一堵墙,i从2开始不断右移到这堵“墙”,每次都要进行 x%i的计算,若结果为0,说明ix的因数,x是合数。

 

质数数量

难度升级,嘣嘣嘣嘣~

❓如果给定的数字是一个小于 263的数字,限定1000ms内判断出它是否为一个素数,那么还可以使用刚才的朴素试除法吗?

课后篇

1.1 更优的试除法

上过课的你肯定知道了更好的试除法,不需要试验到x-1,而只需要试验到x。时间复杂度也随之变为O(x)

可以理解为,墙从x1的位置移动到了x的位置。

 

优化后的试除法,对于预习篇中1个的较大数字够用了,但是如果要是判断n个数字是否为质数,当n的大小为106时,整体时间复杂度为O(nn),又会超时。要解决这个问题,就需要来继续学习筛法。

1.2 朴素筛法

所谓筛法,把所有不是质数的数筛去,剩下的就是质数了。对于两个大于 1 的整数 i,j , ij一定不是质数。由此可以得到一个朴素的筛法。

朴素筛的算法为O(nlogn)。这个算法存在一些重复的计算,比如10即是2,也是5的倍数,这样就被标记了2次。又比如100,就要被2,4,5,10,20,25,50标记7次。越大的数字被标记的次数越多。

观察朴素的筛法能够得到一个启发,一个合数必定有一个质因子。那么就只用质数进行筛,这个效率就能提高了。这种想法就是埃式筛。

1.3 埃拉托斯特尼筛法(sieve of Eratosthenes)

埃式筛得名于古希腊数学家埃拉托塞尼(Eratosthenes),他计算了地球的周长,并且设计了现在为人熟知的经纬系统。

埃式筛用来找出一定范围的所有质数,它的原理非常简单,从2开始,将每个质数的倍数标记成合数。时间复杂度为O(loglogn)

实现的过程中先定出要筛数值n,找出n以内的素数p1,p2,...,pk。先用2去筛,剔除2的所有倍数,再用3去筛,直到剔除了pk的所有倍数为止。

下面这张动图能够帮助我们理解这个过程:

 

1.4 线性筛

仔细观看埃式筛的过程,比如数字12和18就被2和3各自筛掉一次,令一个合数x只被它的最小质因子px筛出,就得到了线性筛,时间复杂度为O(n)

x 的最小质因子为 px ,例如 p9=3,p16=2 。那么在线性筛中,一个合数 x 会且仅会在i=x/px的时候筛去

❓为什么增加一句判断就可以结束内层循环呢

证明充分性,合数 x 会在 i=x/px 的时候筛去。显然有 x/pxpx ,否则 x/px 的最小质因子一定比 px 小,且它也是 x 的一个质因子,那么 x 的最小质因子就不是 px,这与 pxx 最小质因子矛盾。

证明充分性,合数 x 仅会在 i=x/px 的时候筛去。设 px+k 是一个大于 pxx 的质因子,那么当 i=x/px+k 时,在枚举到 px+k 之前,内存循环已经 break掉了。考虑因为 px+kpx 都是质数,所以互质,且同时是 x 的质因子,所以 px 也一定是 x/px+k 的质因子,否则和算术基本定理矛盾,那么当枚举到 px 时,就整除 i 了,不会再枚举到 px+k

综上对于每一个合数,都只会被`st[i*primes[j]] = 1标记一次,实际执行不超过n次,整个算法复杂度不超过O(n)

1.5 必须要完成的作业

作业 * 5
阅读程序
填空题
素数的个数
质因数分解
第n小的质数

1.6 更多的练习

练习题 * 1
区间内的真素数

挑战篇

真题挑战

2021年CSP-J初赛第18题,阅读程序,原题有视频题解

假设输入的x是不超过1000的自然数,完成下面的判断题和单选题: •判断题 1)若输入不为”1”,把第12行删去不会影响输出的结果。() A.正确
B.错误

2)第24行f[i * k] = f[i] / c[i * k] * (c[i * k] + 1)中的” f[i]/c[i*k]”可能存在无法整除而向下取整的情况。() A.正确
B.错误

3)在执行完init()后,f数组不是单调递增的,但g数组是单调递增的。() A.正确
B.错误

•单选题 4)init函数的时间复杂度为()。 A.O(n)
B.O(nlogn) C.O(nn) D.O(n2)

5)在执行完init() 后,f[1],f[2],f[3]......f[100]中有()个等于2。 A.23
B.24
C.25
D.26

6)当输入”1000”时,输出为()。 A.”15 1340”
B.”15 2340”
C.”16 2340”
D.”16 1340”