关于素数的埃氏筛法/区间筛法 C++(代码实现和详解)

本文介绍了两种高效的素数筛法,适用于程序竞赛和大规模素数查找。首先讲解了埃氏筛法,用于找出指定范围内所有素数,然后详细阐述了区间筛法,适用于处理不定区间的素数计数问题。通过实例代码展示这两种算法的实现,帮助读者理解和应用。

前言

如果只对一个整数进行素性测试,通常O(n^1/2)的算法便足够了。而程序竞赛设计的主要是埃氏筛法等更高效的算法。如果要对许多整数进行素性测试,则需要利用更加高效的算法,此次以例题为媒介,介绍埃氏筛法和区间筛法。

一:埃氏筛法

eg:题目描述  

给定整数n,请问n以内有多少个素数?

n<=10^6

看到这,你可能会轻蔑的笑了,就这题,自己分分钟秒杀。但是请别急,下面介绍的埃氏算法,能让你更快解决。

埃氏算法氏和辗转相除法一样古老的算法,其大致思路如下

首先,将2~n范围内的所有数都写下来,存入一张线性表里(用一维数组实现)。其中最小的数字2是素数。将表中2的倍数都划去,当然也包括其本身。之后表中剩余的最小数字是3。它显然也是素数。那么继续将所有3的倍数划去。同理,依次类推,每次表中剩下的最小数字m都是素数,然后将表中所有的m的倍数划去。如此反复操作,便能筛出n以内的所有素数。

埃氏筛法代码实现

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int prime[maxn];//存素数 
int is_prime[maxn];//is_prime[i]=1即表示i为素数 
int n; 
int main(){
	
	scanf("%d",&n);
	int p=0;//表示筛出来的素数的位数 
	for(int i=2;i<=n;i++)is_prime[i]=1;//从2开始初始化,0和1显然非素数非合数 
	
	f
<think>好的,我需要解决用户关于埃氏筛法素数的例题代码实现的请求。首先,我得回忆一下埃氏筛法的基本原理,确保自己理解正确。埃氏筛法是通过标记合数来筛选素数,从2开始,将每个素数的倍数都标记为非素数,这样剩下的就是素数了。用户提到了几个引用内容,里面包含不同的代码示例区间筛的说明。我需要参考这些内容,但用户真正需要的是例题或代码实现。因此,我应该先给出一个标准的埃氏筛法代码,可能结合引用中的例子,比如引用[1][2]中的代码,但要注意用户可能希望看到的是C++或Java的实现,不过用户提供的示例中有Python的快速排序,所以可能也需要Python的代码?不过根据引用中的代码C++Java的示例较多,用户的问题可能偏向于算法实现,所以应该选择常见的语言,比如C++或Python。接下来,我需要确保代码正确,符合埃氏筛法的逻辑。例如,初始化标记数组,将01标记为非素数,然后从2开始循环,如果当前数未被标记,则将其倍数全部标记为合数。引用[1][2]中的代码都是这样的结构,需要注意循环的起始点步长是否正确。 然后,用户可能需要例题,比如如何用埃氏筛法求解某个范围内的素数,或者处理大区间的筛(如引用[4]中的区间筛)。这里可能需要给出一个具体的例子,比如求n以内的素数,或者解决某个问题,比如统计素数的数量,或者输出所有素数。另外,用户可能希望看到代码的解释,说明每一步的作用,这样他们可以更好地理解。例如,初始化数组,标记01,然后遍历每个数,如果是素数就标记其倍数。同时,时间复杂度的解释,埃氏筛法的时间复杂度是O(n loglog n),这可以作为补充说明。还需要注意用户提到的LaTeX格式要求,所有行内数学表达式要用$...$,比如时间复杂度写成$O(n\log\logn)$,而独立公式用$$...$$。例如,在解释算法复杂度时可能需要用到。可能还需要考虑例题的应用场景,比如解决LeetCode上的某个问题,例如LeetCode204题“计数素数”,这正是埃氏筛法的典型应用。可以给出这个例题的解决方案,结合代码实现,这样用户可以看到实际应用。另外,引用[4]提到的区间筛可能是一个扩展内容,如果用户的问题涉及到大区间的素数筛选,可以简要提及,并提供相应的例题或代码。例如,求区间[L,R]内的素数,其中R很大,但区间长度较小的情况,这时候可以使用区间筛,先筛出√R以内的素数,再用这些素数去筛区间内的合数。最后,生成相关问题需要考虑用户可能进一步的问题,比如埃氏筛法的优化(如引用中的代码是否有优化空间),时间复杂度分析,与其他筛的比较(如欧拉筛),或者错误处理(如输入范围过大时的内存问题)等。</think>### 埃氏筛法素数详解 #### 一、算法原理 埃氏筛法通过标记合数实现素数筛选。步骤如下: 1. 初始化标记数组`a[]`,默认所有数都是素数(`false`) 2. 将01标记为非素数(`true`) 3. 从2开始遍历,若当前数未被标记为合数,则将其所有倍数标记为合数 数学依据:任意合数$n$必有小于等于$\sqrt{n}$的质因数[^4] #### 二、标准代码实现C++) ```cpp #include <iostream> #include <cstring> using namespace std; const int N = 1e7 + 5; // 根据问题规模调整 bool a[N]; // false表示素数 void eratosthenes(int n) { memset(a, 0, sizeof(a)); a[0] = a[1] = true; // 标记非素数 for(int i = 2; i*i <= n; i++) { // 优化:只需遍历到√n if(!a[i]) { for(int j = i*i; j <= n; j += i) // 从i²开始标记 a[j] = true; } } } ``` **时间复杂度**:$O(n \log \log n)$[^1] #### 三、典型例题 **LeetCode 204. 计数素数** 题目:统计所有小于非负整数n的质数的数量 解: ```cpp class Solution { public: int countPrimes(int n) { if(n <= 2) return 0; vector<bool> isPrime(n, true); isPrime[0] = isPrime[1] = false; for(int i = 2; i*i < n; i++) { if(isPrime[i]) { for(int j = i*i; j < n; j += i) isPrime[j] = false; } } return count(isPrime.begin(), isPrime.end(), true); } }; ``` #### 四、区间筛(处理超大范围) **例题**:求区间$[L, R]$内的素数,其中$1 \leq L \leq R \leq 10^{12}$且$R-L \leq 10^6$ ```cpp void interval_sieve(long long L, long long R) { vector<bool> isPrime(R-L+1, true); if(L == 0) isPrime[0] = false; if(L <= 1) isPrime[1-L] = false; // 先用普通筛得到√R内的素数 int max_p = sqrt(R); vector<bool> sieve(max_p+1, true); for(int p=2; p<=max_p; p++){ if(sieve[p]){ for(long long j=max(2LL*p, (L+p-1)/p*p); j<=R; j+=p) isPrime[j-L] = false; for(int j=p*p; j<=max_p; j+=p) sieve[j] = false; } } // 输出结果 for(long long i=L; i<=R; i++) if(isPrime[i-L]) cout << i << endl; } ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Prudento

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值