题目链接:http://poj.org/problem?id=2689
题目大意:
数论是数学的一个分支,是研究数的性质。其中素数领域的研究几千年来一直吸引着人们的注意力。一个素数的除了自己和1以外没有别的整数可以整除它的数,最开始的素数有2,3,5,7等,但很快将变得很稀疏。一个有趣的问题是素数在不同范围内的密度。相邻素数是两个素数之间没有别的素数,如2和3就是相邻素数。
该程序将输入两个数,L和U(1<=L<U<=2 147 483 647),要找出两个相邻素数C1和C2(L<=C1<C2<=U)是距离最小的(也就是说C2-C1最小)。如果最下距离的相邻素数不唯一,选择最初的。还需要找出两个相邻素数D1和D2(L<=D1<D2<=U)是距离最大的(同样在有多对的情况下选择最初的)。
输入:
每行两个正整数L和U,其中L和U的差不超过1 000 000。
输出:
对于每组L和U,如果没有相邻素数输出There are no adjacent primes.否则输出给定的两个相邻的素数。
输入样例:
2 17
14 17
输出样例:
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
分析:
其实本题的思路很明确:在给定范围内,找出期间所有的素数,然后把素数间的最大距离、最小距离找出来。
显而易见,找出一个区间的所有素数要用到筛法,但具体到本题,因为数据区间上限达到21亿,不能将这区间所有的素数存下来,只能针对本题区间长度小于1 000 000这一范围把给定区间内的素数筛出来。
使用筛法筛掉区间[ L,U ]内的所有非素数因子(因为一个非素数是被它最小的素因子筛掉的),2 147 483 647内的数或者是素数,或者是能被sqrt(2 147 483 647)≈46341内的素数整除,也就是说,区间[ L,U ]内的所有非素数因子都在46341内。
预先打印46341内的所有素数,然后用这些素数去筛掉制定区间内的所有非素数。
根据素数分布定理:1 000 000个数中最多有80 000(≈n/ln(n))个素数。
实现代码如下:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define maxn 50000 #define INF 0x7fffffff int prime1[maxn],nprime1; bool isprime[maxn*20]; void init_prime1() { long long i,j; nprime1=0; memset(isprime,1,sizeof(isprime)); for(i=2;i<maxn;i++) if(isprime[i]) { prime1[++nprime1]=i; for(j=i*i;j<maxn;j+=i) isprime[j]=0; } } long long l,u; long long prime2[1000001]; int nprime2; void init_prime2() { long long i,j,b; memset(isprime,1,sizeof(isprime)); for(i=1;i<=nprime1;i++) { b=l/prime1[i]; while(b*prime1[i]<l||b<=1) b++; for(j=b*prime1[i];j<=u;j+=prime1[i]) if(j>=l) isprime[j-l]=0; } if(l==1) isprime[0]=0; } void solve() { long long ans_min=INF,ans_max=-INF; long long minl,minr,maxl,maxr; init_prime2(); nprime2=0; for(int i=0;i<=u-l;i++) if(isprime[i]) prime2[++nprime2]=i+l; if(nprime2<=1) puts("There are no adjacent primes."); else { for(int i=1;i<nprime2;i++) { if(prime2[i+1]-prime2[i]<ans_min) { ans_min=prime2[i+1]-prime2[i]; minl=prime2[i]; minr=prime2[i+1]; } if(prime2[i+1]-prime2[i]>ans_max) { ans_max=prime2[i+1]-prime2[i]; maxl=prime2[i]; maxr=prime2[i+1]; } } printf("%lld,%lld are closest, %lld,%lld are most distant.\n",minl,minr,maxl,maxr); } } int main() { init_prime1(); while(scanf("%lld%lld",&l,&u)!=-1) solve(); return 0; }