首页 > 代码库 > Poj2689筛素数

Poj2689筛素数

题目大意:

给定一个区间l,r,求这个区间内相邻的质数中最近的两个和最远的两个.区间范围是1-2^31,区间的长度最多是10^6.

思路:

刚开始对筛选法的理解不深,不知道如何筛选任意一段区间的素数,看了题解恍然大悟,原来用的筛选法总是筛选从1-n的素数,对于为何这样筛选理解不深刻.说下1-n的筛选法,就是用一个数组is_prime[1..n]标记1-n中哪个是素数哪个不是,从2(第一个素数)开始扫描,所有2的倍数都不是素数,那么下一个素数是谁?就是我们向后从is_prime[]中找到的第一个是素数的数.然后用这个素数筛掉后面是它倍数的数.理解了这个原理之后,就可以提前处理一下一定范围内的素数,然后直接用这个范围的素数对给定的任意区间进行筛选就可以了.

针对这个题,最大范围是10^9,那么只要求出sqrt(2^31)内的所有素数就可以筛选任意一个区间的素数了。

这题对筛素数的理解提高不少.

下面是ac代码

 1 #include <iostream> 2 #include <cstdio> 3 #include <math.h> 4 #include <stdlib.h> 5 #include <string.h> 6 using namespace std; 7 #define maxn 500005 8 #define maxl 10000005 9 bool is_prime[maxl];10 int main()11 {12     int prime[maxn];13     memset(is_prime,1,sizeof(is_prime));14     for(int i=2;i<=sqrt(500000);i++)15      if(is_prime[i])16       for(int j=i*2;j<=500000;j+=i)17        is_prime[j]=0;18     int t=0;19     for(int i=2;i<=500000;i++)20      if(is_prime[i]) {prime[++t]=i;}21     int L,U;22     while(~scanf("%d%d",&L,&U))23     {24       memset(is_prime,1,sizeof(is_prime));25       if(L==1) is_prime[0]=0;26       for(int i=1;i<=t;i++)27       {28         if(prime[i]>sqrt(U)) break;29         __int64 start=1ll*L/prime[i]*prime[i];30         if(start<L) start+=prime[i];31         for(__int64 j=start;j<=U;j+=prime[i]) {if(prime[i]!=j) is_prime[j-L]=0;}32       }33       int minlen1,minlen2,maxlen,minlen,maxlen1,maxlen2,prenum=-1;34       maxlen=-1;35       minlen=0x7fffffff;36       for(int i=0;i<=U-L;i++)37         if(is_prime[i])38         {39          if(prenum==-1) prenum=i;40          else41          {42            if(i-prenum>maxlen) {maxlen=i-prenum;maxlen1=prenum;maxlen2=i;}43            if(i-prenum<minlen) {minlen=i-prenum;minlen1=prenum;minlen2=i;}44            prenum=i;45          }46         }47       if(maxlen==-1||minlen==0x7fffffff) printf("There are no adjacent primes.\n");48       else49        printf("%d,%d are closest, %d,%d are most distant.\n",minlen1+L,minlen2+L,maxlen1+L,maxlen2+L);50     }51     return 0;52 }

 

Poj2689筛素数