题目链接

http://poj.org/problem?id=2689

解题思路

前置知识:任何一个合数n都至少有一个质因子小于等于根号n;
因为l和r的范围是1 ~ 2^31,范围太大,显然不能算出1 ~ 2^31的素数再枚举,但是发现r与l的差很小,1e6。
我们的大致思路:
标记l ~ r区间内的合数,未被标记的就是质数,我们再枚举质数之间的差值的大小并记录,输出。
难点是如何标记l ~ r区间内的合数,
假设i是l ~ r区间内的合数,则有i的一个质因子pi在2 ~ 根号i之间,i最大可能取r,所以l ~ r区间内任意一个合数的一个质因子一定在2 ~ 根号r之间。那么对于r最大为2147483647,那么我们就统计1 ~ 根号2147483647区间内的质数。
对于2 ~ 根号r之间的所有质数p,把l ~ r区间内能被p整除的数标记下来,这些就是l ~ r区间内的合数,即标记i * p ( ceil(l/p) <= i <= floor(r/p) )
未被标记的为质数,对相邻的质数两两比较,找出差值最大的即可。

细节实现在代码中有注释

AC代码

#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long

using namespace std;
const int N=1e6+100;

int mx,mn,l,r,mxl,mxr,mnl,mnr,cnt,cntp;
bool vis[N];
int p[50010];
ll prime[50010]; 

void Prime()//欧拉筛 
{
    memset(vis,0,sizeof vis);
    for(int i=2;i<=50000;i++) 
    {
        if(!vis[i]) prime[++cnt]=i;
        for(int j=1;j<=cnt;j++)
        {
            if(i*prime[j]>50000) break;
            vis[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}

int main()
{
    Prime();
    while(cin>>l>>r)
    {
        mn=2147483647,mx=0; cntp=0;
        memset(vis,0,sizeof vis);
        if(l==1) vis[0]=1;//特判一下,如果l=1,那么在收集l~r之间的素数时,因为l=1,vis[1-l]=0,!vis=1,所以1也会被算作素数 

        for(int i=1;prime[i]*prime[i]<=r;i++)//与for(int i=1;i<=cnt;i++)的效果相同,这样写不用开LL,但是按照我的写***出现int*int的范围超过int的情况,出现RuntimeError的情况,所以prime数组要开LL 
        {
            for(int j=l/prime[i];j<=r/prime[i];j++)
            if(j>1) vis[j*prime[i]-l]=1;
        }

        for(int i=l;i<=r;i++)
        {
            if(!vis[i-l]) p[++cntp]=i;
            if(i==r) break;//int最大为2147483647,如果再+1,变成-2147483648,会无限循环下去;这里直接break是防止当输入的r=2147483647的情况 
        }

        for(int i=2;i<=cntp;i++)
        {
            int dis=p[i]-p[i-1];
            if(dis>mx) mxl=p[i-1],mxr=p[i],mx=dis;
            if(dis<mn) mnl=p[i-1],mnr=p[i],mn=dis; 
        }

        if(!mx) cout<<"There are no adjacent primes."<<endl;
        else cout<<mnl<<","<<mnr<<" are closest, "<<mxl<<","<<mxr<<" are most distant."<<endl;
    } 
}

总结

要学会的思想:
要求素数,我们可以通过排除合数求素数;
任何一个合数n都至少有一个质因子小于等于根号n;