1. 程式人生 > >【POJ 2689】Prime Distance【數論,數學】

【POJ 2689】Prime Distance【數論,數學】

題目大意:

思路:

這道題真的是煩。。。
這裡寫圖片描述
這裡寫圖片描述
MLE和RE了超級多次,最後發現是一個極其不起眼的東西。。。
這道題l,r231,但是rl106,所以可以考慮從l,r方面入手。
首先我們知道n的質因子列舉到n就可以了,那我們可以先將不大於231次方的質數用線性篩篩出來,時間複雜度O(r),約為O(47000)
然後對於每一組資料,我們先從列舉每個質數,再從lr列舉,每次直接加prime[i],然後被列舉到的數就絕對是合數。這裡的理論時間複雜度是O((rl)r),語約為

O(47000000000),完全會T。但是這只是理論,實際來說,當r=231時,所有列舉的質數約為5000個,第二重循壞最多執行500000次,最少執行1次,平均約為10次!(經程式輸出)
那麼這一段的時間複雜度就約為O(50000),但是還是有一些卡時。
當然你還可以用goto再簡化。在POJ上評測加了goto會少20ms(當然並不建議用goto)。
之後我們就求出了lr之間的所有質數,那麼接下來暴力列舉就可以啦!

程式碼:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream> #include <algorithm> #define ll long long #define M 1000020 #define Inf 1e16 using namespace std; ll l,r,m,sum,minn,maxn,prime[M],v[M],tail,max_r,max_l,min_r,min_l; bool ok,p[M]; void find_prime(ll n) //離線求質數(線性篩) { for (ll i=2;i<=n;i++) { if (!v[i]) { prime[++m]=i; v[i]=i; } for
(ll j=1;j<=m;j++) { if (prime[j]>v[i]||i*prime[j]>n) break; v[i*prime[j]]=prime[j]; } } } int main() { find_prime(50000); while (~scanf("%lld%lld",&l,&r)) { sum=r-l+1; memset(p,0,sizeof(p)); if (l==1) //特判,1不是質數 { p[1]=1; sum--; } for (ll i=1;prime[i]<=sqrt(r);i++) for (ll j=l+(prime[i]-(l%prime[i]))%prime[i];j<=r;j+=prime[i]) //直接求出第一個質數,然後就每次加prime[i] { if (sum<2) goto stop; //不建議使用 if (j<0||prime[i]==j) continue; if (!p[j-l+1]) sum--; p[j-l+1]=true; } stop: if (sum<2) { printf("There are no adjacent primes.\n"); continue; } minn=Inf; maxn=-Inf; tail=-1; for (ll i=l;i<=r;i++) //爆枚 if (!p[i-l+1]) { if (tail>-1) { if (i-tail>maxn) { maxn=i-tail; max_l=tail; max_r=i; } if (i-tail<minn) { minn=i-tail; min_l=tail; min_r=i; } } tail=i; } printf("%lld,",min_l); printf("%lld are closest, ",min_r); printf("%lld,",max_l); printf("%lld are most distant.\n",max_r); } return 0; }