解题思路:

题目要我们筛出L-R范围内的素数,那么我们只要将这个区间中的合数踢出去不就结束了吗

说起判断合数,我就想到了美猴王合数的一个性质:可以分解为两个不为1且不等于本身的因子相乘 即 n=a*b(n为合数).下证之:

设a<=b 则a * a<a*b

又因a* b=n,则a* a<=n*n

即a<=根号n

因此,在1-根号n的范围之中我们必能找到n的一个质因子

所以,我们只需要在1-根号R范围中筛出所有的质数(剩下的即为合数),然后用我们已经筛出来的因子去在L-R的范围中求出所有的合数,剩下来的即为我们要找的质数,而R的最大值大约为20亿,所以我们只用求(1-50000中的质数就可以拿他们来使用了!)

1.筛出1-50000中的所有质数,并且对合数打上标记.

2.在L-R的范围呢用我们已求出的质数筛出其中的合数(设p为质数,则i*p一定不为质数),并对其打上标记

3.遍历L-R,没有打标记的元素即为我们所求的素数


注意事项:

参考代码:

#include <bits/stdc++.h>

typedef long long LL;

using namespace std;

int prime[100001];

bool vis[1000010];

int oul(int n,int a[]){//欧拉筛筛出素数

for(int i=2;i<=n;i++){

if(!vis[i]){

vis[i]=1;

prime[++prime[0]]=i;//用prime[0]记录素数个数,从prime[1]开始存储素数

}
for(int j=1;j<=prime[0]&&i*prime[j];j++){

vis[i*prime[j]]=1;

if(i%prime[j]==0) break;

}
return prime[0];
}
int main()
{
memset(prime,0,sizeof(prime));

int cnt=oul(50000,prime);

LL L,R;

cin>L>>R;

L=L==1?2:L;//特判L=1时,将L赋值为2,因为1不是素数。如果不这样,下面会算入1为素数

memset(vis,0,sizeof(vis));//初始化数组

for(int i=1;i<=cnt;i++){

for(LL j=max((LL)2,(L-1)/prime[i]+1)*prime[i];j<=R;j+=prime[i]){//j的初始值是为了找到开始筛的数字

vis[j-L]=1;//我们从大于L的最小的能被prime[i]整除的数开始,标记合数

}
}
int ans=0;

for(LL i=L;i<=R;i++){

if(vis[i-L]==0) ans++;//剩下没有赋值为1的即为素数,计算素数个数

}
cout<<ans;

return 0;
}


点赞(0)
 

0.0分

1 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论