当前位置:   article > 正文

算法提高 找素数 Eratosthenes素数筛法

算法提高 找素数

题目链接

问题描述

  给定区间[L, R] , 请计算区间中素数的个数。

【分析】
对于这样的限制,直接枚举判断会超时:需要判断10^6个整数,而每个整数还需要花费一定的时间判断是否为素数。用Eratosthenes筛法构造1~n的素数表。筛法的思想特别简单:对于不超过n的每个非负整数p,删除2p, 3p, 4p,…,当处理完所有数之后,还没有被删除的就是素数。如果用vis[i]表示i已经被删除,筛法的代码可以写成: 

  1. memset(vis, 0, sizeof(vis));
  2. for(int i = 2; i <= n; i++)
  3. for(int j = i*2; j <= n; j+=i) vis[j] = 1;

       尽管可以继续改进,但这份代码已经相当高效了。为什么呢?给定外层循环变量i,内层循环的次数是。这样,循环的总次数小于。这个结论来源于欧拉在1734年得到的结果: ,其中欧拉常数γ≈0.577218。这样低的时间复杂度允许在很短的时间内得到10^6以内的所有素数。

       下面来改进这份代码。首先,在“对于不超过n的每个非负整数p”中,p可以限定为素数——只需在第二重循环前加一个判断if(!vis[i])即可。另外,内层循环也不必从i*2开始——它已经在i=2时被筛掉了。改进后的代码如下:

  1. int m = sqrt(n+0.5);
  2. memset(vis, 0, sizeof(vis));
  3. for(int i = 2; i <= m; i++) if(!vis[i])
  4. for(int j = i*i; j <= n; j+=i) vis[j] = 1;

这里有一个有意思的问题:给定的n,c的值是多少呢?换句话说,不超过n的正整数中,有多少个是素数呢?
素数定理:
其中,π(x)表示不超过x的素数的个数。上述定理的直观含义是:它和x/lnx比较接近——对于算法入门来说,这已足够。

  1. #include <cstdio>
  2. const int N = 1000000+5;
  3. bool notPrime[N],smallPrime[N];
  4. int main(int argc, char** argv) {
  5. int L, R;
  6. scanf("%d%d",&L,&R);
  7. for(long long i = 2; i*i <= R; i++){
  8. if(!smallPrime[i]){
  9. for(long long j = i*i; j*j <= R; j += i) smallPrime[j] = true;
  10. for(long long j = max(i,((L-1)/i +1))*i; j <= R; j += i)
  11. notPrime[j-L] = true;
  12. }
  13. }
  14. int cnt = R-L+1;
  15. for(int i = 0; i <= R-L; i++) cnt -= notPrime[i];
  16. printf("%d\n",cnt);
  17. return 0;
  18. }

输入格式

  两个数L和R。

输出格式

  一行,区间中素数的个数。

样例输入

2 11

样例输出

5

数据规模和约定

  2 <= L <= R <= 2147483647 R-L <= 1000000

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/75203
推荐阅读
相关标签
  

闽ICP备14008679号