poj 2689 Prime Distance(区间素数筛)
Description
The branch of mathematics called number theory is about properties of numbers. One of the areas that has captured the interest of number theoreticians for thousands of years is the question of primality. A prime number is a number that is has no proper factors (it is only evenly divisible by 1 and itself). The first prime numbers are 2,3,5,7 but they quickly become less frequent. One of the interesting questions is how dense they are in various ranges. Adjacent primes are two numbers that are both primes, but there are no other prime numbers between the adjacent primes. For example, 2,3 are the only adjacent primes that are also adjacent numbers.
Your program is given 2 numbers: L and U (1<=L< U<=2,147,483,647), and you are to find the two adjacent primes C1 and C2 (L<=C1< C2<=U) that are closest (i.e. C2-C1 is the minimum). If there are other pairs that are the same distance apart, use the first pair. You are also to find the two adjacent primes D1 and D2 (L<=D1< D2<=U) where D1 and D2 are as distant from each other as possible (again choosing the first pair if there is a tie).
Your program is given 2 numbers: L and U (1<=L< U<=2,147,483,647), and you are to find the two adjacent primes C1 and C2 (L<=C1< C2<=U) that are closest (i.e. C2-C1 is the minimum). If there are other pairs that are the same distance apart, use the first pair. You are also to find the two adjacent primes D1 and D2 (L<=D1< D2<=U) where D1 and D2 are as distant from each other as possible (again choosing the first pair if there is a tie).
Input
Each line of input will contain two positive integers, L and U, with L < U. The difference between L and U will not exceed 1,000,000.
Output
For each L and U, the output will either be the statement that there are no adjacent primes (because there are less than two primes between the two given numbers) or a line giving the two pairs of adjacent primes.
Sample Input
2 17 14 17
Sample Output
2,3 are closest, 7,11 are most distant. There are no adjacent primes.
解题思路:题目的意思就是给出区间[L,U],要求分别找出最近距离、最远距离的一对相邻素数,其中区间[L,U]长度不超过1e6,且L,U∈[1,2147483647]。由于L,U允许有最大值,而在堆区数组也开不了这么大的内存,所以应该考虑区间筛法。由埃氏筛的定义可知:通过枚举不大于sqrt(n)内的所有素数,将素数的倍数一一筛掉,最后剩下的都是素数。利用这个特点,我们可以先做好[2,sqrt(U)]的素数表,然后从[2,sqrt(U)]的表中筛得素数的同时,也将其倍数从[L,U]的表中划去(这里由于开不了很大的数组,所以区间[L,R]中每个值即下标整体向左偏移了L个单位,这样就够标记区间长达1e6个元素了,详解看代码),那么最后剩下的就是区间[L,U]内的素数了。注意:必须特判L,因为题目中要求输出相邻一对素数之间的距离,前提必须是素数,而1不是素数,所以区间左端点值最小为2。
AC代码:
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 #include<cstdio> 5 using namespace std; 6 typedef long long LL; 7 const int maxn=1e6+5; 8 LL L,U,prime[maxn];bool isp1[maxn],isp2[maxn]; 9 int segment_sieve(LL L,LL R){//区间筛法 10 memset(isp1,true,sizeof(isp1));//isp1标记[2,sqrt(R)]内的素数 11 memset(isp2,true,sizeof(isp2));//isp2标记区间[L,R]中的素数,其中isp2[j-L]=true <=> j是素数 12 if(L<2)L=2;//注意左端点必须是从2开始,必须特判这种情况 13 for(LL i=2;i*i<=R;++i){//枚举不大于sqrt(R)即可(埃氏筛) 14 if(isp1[i]){ 15 for(LL j=i*i;j*j<=R;j+=i)isp1[j]=false;//筛[2,sqrt(R)],选出这个区间的所有素数,然后去筛掉区间[L,R]的所有合数 16 for(LL j=max(2LL,(L+i-1)/i)*i;j<=R;j+=i)isp2[j-L]=false; 17 //(L+i-1)/i得到最接近L的i的倍数,最小是i的2倍,然后筛掉区间[L,R]中素数i的倍数(合数) 18 } 19 } 20 int cnt=0;//记录区间[L,R]中素数的个数 21 for(LL i=0;i<=R-L;++i)//0~R-L 22 if(isp2[i])prime[cnt++]=i+L;//保存区间[L,R]中的所有素数 23 return cnt; 24 } 25 int main(){ 26 while(~scanf("%lld%lld",&L,&U)){ 27 int num=segment_sieve(L,U); 28 if(num<2)printf("There are no adjacent primes.\n");//如果个数小于2,说明没有相邻的素数,直接输出 29 else{//依次去枚举区间[L,U]中所有相邻素数的距离 30 LL mlt=0,mrt=0,nlt=0,nrt=0,f1=0,f2=maxn; 31 for(int i=1;i<num;++i){ 32 if(prime[i]-prime[i-1]>f1)//最远距离的一对相邻素数 33 f1=prime[i]-prime[i-1],mlt=prime[i-1],mrt=prime[i]; 34 if(prime[i]-prime[i-1]<f2)//最近距离的一对相邻素数 35 f2=prime[i]-prime[i-1],nlt=prime[i-1],nrt=prime[i]; 36 } 37 printf("%lld,%lld are closest, %lld,%lld are most distant.\n",nlt,nrt,mlt,mrt); 38 } 39 } 40 return 0; 41 }