1. 程式人生 > >poj2689兩次篩法

poj2689兩次篩法

我們都知道一次篩法求1-n之間的素數,這個篩法的演算法複雜度為O(N),但題目中的U,L最大值可為整型上限,用純粹的暴力篩法肯定要超時?怎麼辦,用二次篩法。U和L之間的合數,質因子不超過O(L^0.5),於是用篩法選出50000內的素數即可,因為50000的平方大於整形上線了。再用這些素數去篩出U-L之間的合數,剩下的就是U-L之間的素數了,邊篩邊計算兩個素數之間的差,就OK了。另外,尤其小心的是U為1的情況,做素數題往往1是個坑爹的東西。。。附程式碼:

#include <iostream>
#include <cmath>

using namespace std;

const int N=50000;
const int Max=0xfffffff;

int r[1000000],a[N+100],b[N+100],z;

int main()
{
    int a0,b0,i,j;
    for (i=2;i<=N;i++)
        if (!a[i])
        {
                  b[++z]=i;
                  for (j=i*2;j<=N;j+=i) a[j]=1;         
        }
    while (cin>>a0>>b0)
    {
          memset(r,0,sizeof(r));
          int t=0,dis,mmax=-1,mmin=Max,m1,m2;
          for (i=1;i<=z;i++)
          {
              int s,t;
              s=(a0-1)/b[i]+1;
              t=b0/b[i];
              for (j=s;j<=t;j++)
                  if (j>1) r[j*b[i]-a0]=1; 
          }
          int k=-1;
          for (i=0;i<=b0-a0;i++)
              if (!r[i])
              {
                        if (k!=-1)
                        {
                                  dis=i-k;
                                  if (dis>mmax) 
                                  {
                                                mmax=dis;
                                                m1=i+a0;
                                  }
                                  if (dis<mmin)
                                  {
                                               mmin=dis;
                                               m2=i+a0;
                                  }
                        }
                        if (i+a0!=1) k=i;                        
              }
          if (mmax<0)
          {
                     cout<<"There are no adjacent primes."<<endl;
          }
          else
          {
              cout<<m2-mmin<<','<<m2<<" are closest, ";
              cout<<m1-mmax<<','<<m1<<" are most distant."<<endl;
          }
    }
    return 0;
}