素数筛学习笔记
素数筛
埃氏筛法
埃氏筛法(埃拉托色尼筛法)是一种用来求所有小于N的素数的方法。把从2(最小的素数)开始的某一范围的正整数从小到大按顺序排列,逐步筛掉非素数留下素数。
例如一组数:
2、3、4、5、6、7、8、9、10、11、12、13、14、15、16
首先选择最小的一个没有被选择过的数字,表明其为当前最小的素数。
然后从这一列数字中把所有该数字的倍数划掉:
2、3、(4)、5、(6)、7、(8)、9、(10)、11、(12)、13、(14)、15、(16)
然后重新选择数字并重复进行上面的操作。
当选择到5时,因 5 > sqrt(16),则剩下的未被划掉的全部为素数。
代码实现如下:
bool isNotPrime[MAXN];
void init(int n) {
for(int i = 2; i * i <= n; ++i) {
if(!isNotPrime[i]) { //用于选择第一个未被选择过的素数
for(int j = i*i; j <= n; j += i) { //从选择素数值的平方开始
isNotPrime[j] = 1;
}
}
}
//至于为什么从i*i开始筛选,是因为从2i到(i-1)i都在之前被更小的素数筛过了
上述代码很简单,但是一个数字可能会被处理多次: 如对于数字12,会被2、3各划掉一次,处理的时间复杂度还可以进一步优化。
欧拉筛(线性筛)
在埃氏筛的基础上,保证每一个和数都只被它的最小的质因数筛选一次。
在这个算法里除了要列出范围外,还需要维护一个质数表。
例如一列数字:
2、3、4、5、6、7、8、9、10、11、12、13、14、15、16
prime()
依然是从头到尾进行遍历,第一个数字是2,未被划掉,放入质数表中:
(2)、3、4、5、6、7、8、9、10、11、12、13、14、15、16
prime(2, )
然后用当前的数字乘指数表中所有的数字并划掉乘积:
(2)、3、(4)、5、6、7、8、9、10、11、12、13、14、15、16
prime(2,)
下一个数字是3,划掉6和9:
2、(3)、(4)、5、(6)、7、8、(9)、10、11、12、13、14、15、16
prime(2, 3, )
下一个数字是4(划掉的数字依然需要进行遍历,只是不加入质数表)
先划掉8,但不划掉12,12应该被其最小的质因数2划去,而不是当前质数表里的3。
2、3、((4))、5、(6)、7、(8)、(9)、10、11、12、13、14、15、16
prime(2, 3, )
然后继续进行上述的过程即可得到素数表。
代码实现如下:
bool isNotPrime[MAXN];
vector<int> primes;
void init(int n) {
for(int i = 2; i <= n; ++i) {
if(!isNotPrime[i])
primes.push_back(i); //更新素数表
for(int p : primes) {
if(p * i > n) break; //越界判断
isNotPrime[p*i] = 1;
if(i%p == 0) break; //关于这一句的解释在最后
}
}
}
//当i是p的倍数时,i=k*p,如果继续使下一个素数参p'与运算,则i*p'=k*p*p'
//这样和当i=k*p'时的情况会重复
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!