筛质数
c++
筛质数
/* * 素数筛 * 素数、质数定义: * 质数,又叫素数,是指一个大于1的自然数,且除了1和它本身外,不能被其他自然数整除的数。换句话说,就是该数除了1 和它本身以外,不再有其他的因数。 * * 在先前的博客中,我们介绍了试除法 O(sqrt(N)) 判断一个数字是否为素数;以及 O(sqrt(N)) 将数分解为素数,下面我们介绍素数筛。 * * 素数筛判断 1..n 中的数字,分别是否为素数。 * 1. 使用试除法作素数筛 * 我们已知试除法判断一个数字是否为素数的复杂度是 O(sqrt(N)),那么判断 n 个数字,复杂度约为 O(N sqrt(N)) = O(N ^ 1.5)。 * 这是因为试除法 判断第 i 个数字是否为素数,没有充分利用到前 i 个数字的信息 * * 因此可以充分使用了前面素数信息的方法,思想是判断 x 是否为素数,查看 x 之前,并且小于 sqrt(x) 的素数,x是否可以整除。 * * π(x)符号,就是表示小于或等于自然数x的所有素数个数,当x趋于无穷大时,π(x)和x /ln(x)这两个数的比值趋于1。 * 因此复杂度为 O(N log(sqrt(N)) * 2. 埃氏筛 * 使用改进后的试除法作为素数筛是可以,但是 x 老是会整一些除不尽的数,浪费时间,因此我们可以使用质数,否定他的倍数。 * 计算量: * n / 1 + n / 2 + n / 3 + ... + n / n = n logn * 但是加上素数优化,感觉会好很多。 * * 3. 欧拉筛(线性筛) * 欧拉筛和埃氏筛都是一样,利用 st 数组,结合公倍数进行筛选,晒出合数,剩下的就是质数了,他们复杂度的优劣性在于合数被筛选了多少次? * 埃氏筛的算法流程可以看出,对于某个合数,他被筛出的次数为他质因数分解后,质数的个数,如 45 = 3 ^ 2 * 5,他有两个种类的质数,3和5。 * 欧拉筛的出发点在于,能否每个合数只需要筛选一次? * -> 我们使用 最小的质因数 筛选合数,那么这个合数只会被筛选一次。 * 复杂度从名称也可以听出来,为 O(N) * * 4. 实际运行时间分析 * 发现试除法还是耗时长,这是因为试除法所有数字都要试除,不如直接利用 st 方法筛选出他们的倍数方便。 */ #include <iostream> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <cmath> #include <cstdio> using namespace std; const int N = 1000010; int n; vector<int> prime; bool st[N]; // 优化之后的试除法判质数 // @test-time: 231 ms void sample_seive(int n) { prime.clear(); memset(st, false, sizeof st); if (n <= 1) { return; } st[1] = true; for (int i = 2; i <= n; i ++ ) { for (int j = 0; j < prime.size() && prime[j] * prime[j] <= i; j ++ ) { if (i % prime[j] == 0) { st[i] = true; break; } } if (st[i] == false) { prime.push_back(i); } } } // 埃氏筛 // @test-time: 53 ms void ai_sieve(int n) { memset(st, false, sizeof st); prime.clear(); if (n <= 1) { return; } st[1] = true; for (int i = 2; i <= n; i ++ ) { if (st[i] == false) { prime.push_back(i); for (int j = i + i; j <= n; j += i) { st[j] = true; } } } } // 欧拉筛,线性筛 // @test-time: void euler_sieve(int n) { prime.clear(); memset(st, false, sizeof st); if (n <= 1) { return; } for (int i = 2; i <= n; i ++ ) { if (st[i] == false) { prime.push_back(i); } for (int j = 0; prime[j] <= n / i; j ++ ) { // i 这个因数,分解后质因数小于等于 primes[j] st[i * prime[j]] = true; if (i % prime[j] == 0) { break; } } } } int main() { scanf("%d", &n); euler_sieve(n); printf("%d\n", prime.size()); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)