原题链接:蓝桥杯算法提高VIP-找素数
解题思路:
题目要我们筛出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分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复