这是一道关于素数的题目,不过这是运用筛法求素数的方法求解区间内的素数,是一道很好的题目,会让你对筛法求素数有更好的理解(提示:下面的讲解都建立在懂得一般筛法求素数的基础上,所以如果不会,请先学习筛法求素数的算法)。
这题要求相邻素数的最大和最小距离,但只要知道区间的所有的素数,这就很好解决了,所以解题重点在于筛法求一段区间的素数。一般筛法求素数是从2开始的一个区间,但这题左边的区间L可能离2很远,,且U很大,所以不能直接求[2,U]内的全部素数。但我们知道如果想筛2500内的素数,我们只要求出50内的素数,再筛去其余部分的非素数。同样,这里U最大2147483647,如果想筛出[2,2147483647]内的所有素数,那么只要有50000内的素数就可以了(当然2147483647开根号比50000小,我只是凑整到50000),这是筛法求素数能承受的大小,求出50000内的所有素数,那么[2,2147483647]中任意区间的素数同样可以用50000内的素数可以筛出来了。
不过还要注意一个细节,筛法筛除非素数有一个非素数不能筛掉,那就是1,所以如果L是1,必须另外处理。
随便说一句,存储素数的数组该开多大呢,可以用X/㏑X(计算小于X的素数个数)来辅助判断,那个公式只是估计值,一般是偏小,所以必须在此基础上往大里开。
最后谈一下我犯的错误。
开始我的一段代码是如下这样:
k=sqrt(MAX*1.0);
for(i=2;i<=k;i++)
{
if(array[i])
{
prime[len++]=i;
for(j=i+i;j<MAX;j+=i) array[j]=false;
}
}
这里本来想省事,在发现素数时顺便存下来,可是错误在于这里只是存了[2,k]内的素数,而不是[2,MAX]内的素数,检查错误时一直没想到这里会错,导致WA很多次,所以下次对自己很熟悉的地方也不要太大意,尤其是想找到这个问题很简单,输出就能发现,可惜一开始一直很懒,不愿进行输出检查。不过如果想在筛素数时同时存储下来,可以把k换成MAX-1。
AC代码(C++):
#include <cstdlib>
#include <iostream>
#include <cmath>
#define INF 2147483647
#define MAX 50001
using namespace std;
bool array[MAX],array2[1000002];
long long prime[5000],prime2[80000],len,len2;
void mkprime()
{
long long i,j,k;
k=sqrt(MAX*1.0);
len=0;
memset(array,true,sizeof(array));
for(i=2;i<=k;i++)
{
if(array[i])
{
for(j=i+i;j<MAX;j+=i) array[j]=false;
}
}
for(i=2;i<MAX;i++)
{
if(array[i]) prime[len++]=i;
}
}
int main(int argc, char *argv[])
{
long long L,U,i,dis1,dis2,a,b,c,d,tmp;
long long j;
mkprime();
while(cin>>L>>U)
{
memset(array2,true,sizeof(array2));
for(i=0;i<len;i++)
{
if(prime[i]>=L) j=2*prime[i]-L;
else{
tmp=L/prime[i];
j=tmp*prime[i]-L;
while(j<0) j+=prime[i];
}
//下面这种也可以
/*tmp=L/prime[i];
while(tmp*prime[i]<L||tmp<=1) tmp++;
j=tmp*prime[i]-L; */
for(;j<U-L+1;j+=prime[i]) array2[j]=false;
}
if(1==L) array2[0]=false;
len2=0;
dis1=INF;
dis2=-INF;
for(i=0;i<U-L+1;i++)
{
if(array2[i])
{
prime2[len2++]=i;
if(len2>1)
{
if(prime2[len2-1]-prime2[len2-2]<dis1)
{
dis1=prime2[len2-1]-prime2[len2-2];
a=len2-2;
b=len2-1;
}
if(prime2[len2-1]-prime2[len2-2]>dis2)
{
dis2=prime2[len2-1]-prime2[len2-2];
c=len2-2;
d=len2-1;
}
}
}
}
if(len2>1) cout<<prime2[a]+L<<','<<prime2[b]+L<<" are closest, "<<prime2[c]+L<<','<<prime2[d]+L<<" are most distant."<<endl;
else cout<<"There are no adjacent primes."<<endl;
}
system("PAUSE");
return EXIT_SUCCESS;
}
题目:
Time Limit: 1000MS | Memory Limit: 65536K | |
Description
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
Output
Sample Input
2 17 14 17
Sample Output
2,3 are closest, 7,11 are most distant. There are no adjacent primes.