poj 2689 Prime Distance(大數區間素數篩法)
阿新 • • 發佈:2019-01-26
題意:給定區間[L,R],求區間內距離最近的相鄰素數對和距離最遠的相鄰素數對,區間長度不超過1e6。
解題方案:用篩法求出[L,R]的所有素數——利用“合數n一定有小於或等於sqrt(n)的素數因子“這條性質,先預處理出sqrt(2,147,483,647)範圍內的所有素數,然後用它們篩掉所有在區間[L,R]內的合數。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <stack> #include <set> #include <map> using namespace std; #define FOR(i,k,n) for(int i=k;i<n;i++) #define FORR(i,k,n) for(int i=k;i<=n;i++) #define scan(a) scanf("%d",&a) #define scann(a,b) scanf("%d%d",&a,&b) #define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c) #define mst(a,n) memset(a,n,sizeof(a)) #define ll long long #define N 100005 #define mod 1000000007 #define INF 0x3f3f3f3f const double eps=1e-8; const double pi=acos(-1.0); ll L,R; int vis[N*10]; int prime[N],prime1[N*10]; int cnt,cnt1; int Min,Max,minl,minr,maxl,maxr; void Init() { mst(vis,0); cnt=0; FOR(i,2,N) { if(!vis[i]) { prime[cnt++]=i; for(int j=i+i;j<N;j+=i) vis[j]=1; } } } void range_prime()//大數區間篩素數 { mst(vis,0); FOR(i,0,cnt) { ll b=L/prime[i]; if(b*prime[i]<L) //將b*prime[i]定位到第一個大於或等於L的合數的位置 b++; //注意b==0時和b*prime[i]==L並且b==1時的情況 if(b<=1) //這兩條if語句也可以合併為 while(b*prime[i]<L||b<=1) b++; b++; for(ll j=b*prime[i];j<=R;j+=prime[i]) //b>=2 vis[j-L]=1; //節省空間,否則空間複雜度太高 } if(L==1) vis[0]=1; //如果左邊界到了1,需要特判,1不是素數,所以要被篩掉 cnt1=0; for(ll i=L;i<=R;i++) { if(!vis[i-L]) prime1[cnt1++]=i; } } void solve() { range_prime(); Min=INF; Max=0; minl=minr=maxl=maxr=-1; FOR(i,1,cnt1) { int d=prime1[i]-prime1[i-1]; if(d<Min) Min=d,minl=prime1[i-1],minr=prime1[i]; if(d>Max) Max=d,maxl=prime1[i-1],maxr=prime1[i]; } } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); Init(); while(cin>>L>>R) { solve(); if(cnt1<2) printf("There are no adjacent primes.\n"); else printf("%d,%d are closest, %d,%d are most distant.\n",minl,minr,maxl,maxr); } return 0; }