寻找第N质数-分块筛
pos数组是以50000为间隔的前面几个块素数个数,是用之前的代码本地跑出来的,就是说1-5W有多少个素数,1-10w有多少个素数这样子。然后每次输入n找到他在哪个区间内,再单独筛出这个区间内的素数就好了
#include<stdio.h>
#include<queue>
#include<string.h>
#define MIN(a,b) (((a)<(b))?(a):(b))
using namespace std;
int pos[1005]= {-1,5133,9592,……,2998299};
bool prime[60000],seive[60000];
void seg_seive(int L,int R){//区间筛法,传入区间
int len=R-L+1;//区间长度
for(int i=0; i<len; i++) prime[i]=1;//先假定全部质数
if(1-L>=0) prime[1-L]=0;//易错因为1不是素数也不是合数,这也是区间筛的一个易错bug,反正prime[1]=0
for(int i=2; i*i<=R ; i++)//2到根号R扫一次
if(seive[i])//偏移数组中I是质数
for(int j=max(2,(L-1+i)/i)*i; j<=R; j+=i) //第二个易错点,j必须从大于1,因为L可能小于i,但是seive[i]是素数。
prime[j-L]=false;//那么找到区间内的第一个值开始全部标记为假
}
int main(){//五万分界区间
for(int i=2; i<50001; i++) seive[i]=1;//全部标记是质数
for(int i=2; i*i<50001; i++) //预处理
if(seive[i])//是质数
for(int j=2*i; j<50001; j+=i)//从两倍起翻倍
seive[j]=false;//全更新为假
int n,rl=1;
while(~scanf("%d",&n)){//问第N个质数
if(n==0)break;//特判0
int l=0,r=1000;//二分左右界
while(l+1<r){//直至得到POS数组中的LR区间
int mid=(l+r)/2;
if(pos[mid]<n)
l=mid;
else r=mid;
}
int left=l*50000,right=r*50000;//左右界乘五万就是该区间质数数量对应的枚举区间
int x=n-pos[l];//在区间内还有多少个数要扫(必少于五万)
seg_seive(left,right);//传入左右界,得到区间内的质数数量
//printf("%d %d %d\n",left,right,x);
for(int i=left; i<=right; i++){//从左界扫到右界
if(prime[i-left]==1){//偏移LEFT后在PRIME数组中打上了标记即表示是质数
x--;//每扫一个数就减1
if
寻找第N质数-分块筛
最新推荐文章于 2023-09-14 12:01:38 发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)