poj 2689 Prime Distance 素数

来源:互联网 发布:网页美工是做什么的 编辑:程序博客网 时间:2024/05/18 17:57

题意:输入区间[l,u],其中l和u为int范围的整数,区间最大为1000000。求出[l,u]中,相邻素数只差最大和最小的素数对。当存在多个时,输出较小的素数对。

题解:l,u范围太大,不能直接求int范围的素数。而区间间隔比较小,只有1e6,而且对于int范围内的合数来说,最小质因子必定小于2^16。所以可以求出[l,u]中合数,转而求出素数,然后暴力枚举所有素数对即可。

如何求区间[l,u]中的合数:上面已经说了,合数的最小质因子小于2^16,即小于50000。所以先求出小于50000的所有素数。则区间[l,u]中的合数,必定可以表示为小于50000的素数的倍数。对于素数p来说,令a=(l-1)/p+1,b=u/p。则枚举j=a到b,j*p可以枚举所有[l,u]中质因子含有p的合数。枚举所有小于50000的素数,然后用上述方式枚举倍数,即可找出[l,u]中所有的合数。

由于l,u在int范围,所以不能直接用数组标记。需要加个偏移量,取l,则数组大小小于1e6的f[0,u-l],即可标记。

接着枚举区间中所有的相邻素数对即可。

特别注意:由于1不是小于50000的素数的倍数,所以在与合数相斥中,会被当成素数。需要特别处理下。


耗时:79MS

#include <cstdio>#include <cstring>#include <cmath>#include <queue>#include <iostream>#include <algorithm>using namespace std;const int INF=1e9;const int maxn=5e4+10;const int maxm=1e6+10;int l,u,prime[maxn],vis[maxn],f[maxm],t;void init()//求出50000内的素数,int范围内的合数最小质因子必定小于2^16。{    int i,j,k,m;    t=0;    m=(int)sqrt(maxn+0.5);    memset(vis,0,sizeof(vis));    for(i=2;i<=m;i++)    {        if(!vis[i])        {            for(j=i*i;j<maxn;j+=i)            vis[j]=1;        }    }    for(i=2;i<maxn;i++)if(!vis[i])prime[t++]=i;}int main(){    init();    while(cin>>l>>u)    {        if(l==1)l=2;//注意l=1会出问题。        int i,j,k,a,b;        memset(f,0,sizeof(f));        for(i=0;i<t;i++)        {            a=(l-1)/prime[i]+1;            b=u/prime[i];            for(j=a;j<=b;j++)if(j>1)f[j*prime[i]-l]=1;//[l,u]区间小于1e6,而l,u数值范围为int,所以偏移l们就能用数组存了        }        int p=-1,max_ans=-1,min_ans=INF,x1,y1,x2,y2;        for(i=0;i<=u-l;i++)//暴力枚举。。        {            if(f[i]==0)            {                if(p==-1){p=i;continue;}                if(max_ans<i-p){max_ans=i-p;x1=p+l;y1=i+l;}                if(min_ans>i-p){min_ans=i-p;x2=p+l;y2=i+l;}                p=i;            }        }        if(max_ans==-1)cout<<"There are no adjacent primes."<<endl;        else cout<<x2<<","<<y2<<" are closest, "<<x1<<","<<y1<<" are most distant."<<endl;    }    return 0;}


原创粉丝点击