1. 程式人生 > >POJ 2689 Prime Distance (二次?篩素數)

POJ 2689 Prime Distance (二次?篩素數)

Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u
Submit

Status

Practice

POJ 2689
Description
The branch of mathematics called number theory is about properties of numbers. One of the areas that has captured the interest of number theoreticians for thousands of years is the question of primality. A prime number is a number that is has no proper factors (it is only evenly divisible by 1 and itself). The first prime numbers are 2,3,5,7 but they quickly become less frequent. One of the interesting questions is how dense they are in various ranges. Adjacent primes are two numbers that are both primes, but there are no other prime numbers between the adjacent primes. For example, 2,3 are the only adjacent primes that are also adjacent numbers.
Your program is given 2 numbers: L and U (1<=L< U<=2,147,483,647), and you are to find the two adjacent primes C1 and C2 (L<=C1< C2<=U) that are closest (i.e. C2-C1 is the minimum). If there are other pairs that are the same distance apart, use the first pair. You are also to find the two adjacent primes D1 and D2 (L<=D1< D2<=U) where D1 and D2 are as distant from each other as possible (again choosing the first pair if there is a tie).
Input
Each line of input will contain two positive integers, L and U, with L < U. The difference between L and U will not exceed 1,000,000.
Output
For each L and U, the output will either be the statement that there are no adjacent primes (because there are less than two primes between the two given numbers) or a line giving the two pairs of adjacent primes.
Sample Input
2 17
14 17
Sample Output
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.

現在寫這個得簡潔點了qwq廢話太多。。。但是最重要的不是方法還是想到這個方法的過程。。。。

大意:給出區間[l,r]求這個區間裡 相鄰素數差值最小和最大的兩組素數。

樸素想法就是列舉區間每一個數,判斷其是否為素數,判斷的時候是挨著去除之前篩好了的1~2^16的素數(因為一個合數肯定能由多個素數相乘得到)。複雜度應該是 10^6*6000左右吧。
然後就需要考慮怎麼優化的問題。
優化的關鍵點應該放在素數的判斷上。原想法是讓每一個數挨著挨著找它的素數因子,但是這樣會除很多次,這就很像我們最開始對找素數法(列舉)進行優化一樣。用同樣的思維,窩們可以也用篩的方法。因為l~r的區間很小,用已經有的素數去篩這個區間裡的數。這樣每個數只會被訪問一次,不同的素數也只會被用一次。複雜度 P+1E6 。

自己程式碼實現上還有很多細節沒有掌握好.
發現了一個很細節的問題。
看起來列舉l~r的迴圈變數i 定義成int沒有什麼問題。
其實i++很致命。因為r可以等於2^31-1 這是時候i再++,就會超int 然後變成負數。於是又符合i≤2^31-1這個條件了,於是又會接著迴圈。一方面問題是會訪問無效記憶體(下標為負了),另一方面會增加迴圈次數。
所以。。。以後這種擦邊的問題一定要開longlong qwqwq

//  Created by ZYD in 2015.
//  Copyright (c) 2015 ZYD. All rights reserved.
//

#include <cstdio>
#include <cstdlib> #include <iostream> #include <algorithm> #include <cstring> #include <climits> #include <string> #include <vector> #include <cmath> #include <stack> #include <queue> #include <set> #include <map> using namespace std; #define Size 100000 #define ll long long #define mk make_pair #define pb push_back #define mem(array) memset(array,0,sizeof(array)) typedef pair<int,int> P; int prime[65538],used[1000050],ans[1000050]; int l,r,p; int twice(int l,int r){ for(int i=1;i<=p;i++) { int x=prime[i]; // cout<<x<<" "; if(x>r) break; // cout<<l/x<<","<<r/x<<" "; for(int j=l/x;j<=r/x;j++) { if(j*x<l || j<=1) continue; int xx=j*x-l; // cout<<j*x-l<<" "; used[xx]=1; // cout<<xx<<" "; } } return 0; } int main() { freopen("in.txt","r",stdin); p=0;mem(used); for(int i=2;i<=65536;i++) if(used[i]==0) { used[i]=1; for(int j=i+i;j<=65536;j+=i) used[j]=1; prime[++p]=i; // cout<<i<<" "; }cout<<p<<endl; while(cin>>l>>r){ mem(used);mem(ans); twice(l,r); int t=0; int L=l; if (l==1) L++; // cout<<r<<endl; for(ll i=L;i<=r;i++) { cout<<i<<endl; int xx=i-l; // cout<<xx<<" "; if(used[xx]==0) // cout<<xx<<",i="<<i<<" "; { ans[++t]=i; // cout<<xx<<" "<<i<<endl; } } // cout<<used[97]<<endl; if(t<=1){ printf("There are no adjacent primes.\n"); continue; } int maxx=0,minn=2147483647; // cout<<minn<<endl; int min1,min2,max1,max2; for(int i=2;i<=t;i++){ if(ans[i]-ans[i-1]<minn){ min1=ans[i-1]; min2=ans[i]; minn=ans[i]-ans[i-1]; // cout<<minn<<" "; } if(ans[i]-ans[i-1]>maxx){ max1=ans[i-1]; max2=ans[i]; maxx=ans[i]-ans[i-1]; // cout<<maxx<<" "; } }//cout<<endl; printf("%d,%d are closest, %d,%d are most distant.\n",min1,min2,max1,max2); } return 0; }