1. 程式人生 > >POJ2689:Prime Distance——題解

POJ2689:Prime Distance——題解

poj 裏的 namespace ble sin lose 空間 tdi prime

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

題目大意,給不超過int的l,r,其中r-l+1<=1000000,篩出其中的素數,並且求出相鄰素數差值最大和最小的一對。

——————————————————

顯然這是一道篩出l和r之間素數的裸題。

我們發現對於區間裏的一個合數,其最大質因子不會超過50000(不然50000平方就大於2147483647)

秉承著正難則反的思想,篩1-50000素數,然後用一種很神奇的方法判斷掉區間裏的合數,統計素數即可。

判斷方法:

首先我們將每個素數(記為su)平方得到t,一定是合數。

如果發現其<l。

我們就可以t=l/su*su,得到的也一定是合數。

如果此時仍然<l,我們為t+=su,得到的還是合數。

當然如果超了r那就continue;

然後對於t打標記。

然後不斷地t+=su直到超r為止。

可以發現一定能夠篩全合數。

簡略證明:

不斷地加相當於乘。

所以實際上我們在做的就是(例如su=2),就是2*2,2*3,2*4,2*5……這些全是合數。

而且因為起點是平方,所以避免了3*2這樣的重復產生,所以更加的快捷。

#include<cstdio>
#include
<cstring> #include<iostream> #include<cmath> #include<map> #include<algorithm> using namespace std; const int INF=2147483647; int su[50001]={0}; bool he[50001]={0}; int cnt=0; bool vis[1000001]={0}; void Euler(int n){ for(int i=2;i<=n;i++){ if(he[i]==0){ cnt
++; su[cnt]=i; } for(int j=1;j<=cnt&&i*su[j]<=n;j++){ he[su[j]*i]=1; if(i%su[j]==0)break; } } return; } int main(){ Euler(50000); int l,r; while(scanf("%d%d",&l,&r)!=EOF){ memset(vis,0,sizeof(vis)); int ans=0; for(int i=1;i<=cnt&&su[i]<=sqrt(r);i++){ //t接下來無論怎麽變都是合數 int t=su[i]*su[i]; if(t<l)t=l/su[i]*su[i];//t太小的時候就得這樣讓它變大點 if(t<l){ if(t<=r-su[i]){ t+=su[i]; }else continue; } while(t<=r){ vis[t-l]=1; if(t==su[i])vis[t-l]=0;//壓縮空間 if(t<=r-su[i])t+=su[i]; else break; } } if(l==1)vis[0]=1; int p=-1; int x1,y1,x2,y2,ans1=-1,ans2=INF; for(int i=0;i<=r-l;i++){ if(!vis[i]){ if(p==-1){p=i;continue;} if(ans1<i-p){ans1=i-p;x1=p+l;y1=i+l;} if(ans2>i-p){ans2=i-p;x2=p+l;y2=i+l;} p=i; } } if(ans1==-1)cout<<"There are no adjacent primes."<<endl; else cout<<x2<<","<<y2<<" are closest, "<<x1<<","<<y1<<" are most distant."<<endl; } return 0; }

POJ2689:Prime Distance——題解