1. 程式人生 > >數論_質數_POJ2689_Prime Distance

數論_質數_POJ2689_Prime Distance

點此開啟題目頁面

思路分析:

    根據合數N的最小的質因數在區間[2, \sqrt{N}], 因此可篩法求出[2, \sqrt{U}]上所有的素數, 對於該範圍內的每個素數p, 標記[L, U]上為不等於p且為p的倍數的所有的整數, 最終未被標記的就是[L, R]上的素數. 下面給出基於此策略的AC程式碼: (注意第27行為防止數值超過int型的最大值而使用了long long)

//POJ2689_Prime Distance
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
const int MAX = 1e6 + 5, INF = 0x3f3f3f3f;
//ok[i]為0表示L + i - 1為素數, 為1則L + i - 1為合數, prim[i]為1表示i為素數, 為2表示i為合數 
int L, U, ok[MAX + 5], prim[MAX + 5];
int main(){
	//篩法求1...MAX之間的素數
	for(int i = 2; i <= MAX; ++i){
		if(prim[i]) continue;
		prim[i] = 1; for(int j = i; j <= MAX / i; ++j) prim[i * j] = 2;
	} 
	while(~scanf("%d %d", &L, &U)){
		int su = sqrt((double)U);
		//標記L, U之間的所有素數
		memset(ok, 0, sizeof(ok));
		for(int i = 2; i <= su; ++i)
			if(prim[i] == 1) 
				for(int j = L / i + (bool)(L % i); j <= U / i; ++j) 
					if(j > 1) ok[j * i + 1 - L] = 1;
		vector<int> prvec;//儲存L...U之間所有的素數
		for(long long i = 1, j = L; j <= U; ++i, ++j) if(!ok[i] && j >= 2) prvec.push_back(j);
		if(prvec.size() <= 1) cout << "There are no adjacent primes." << endl;
		else{
			int mindis = INF, minpos, maxdis = -INF, maxpos;
			for(int i = 0; i < prvec.size() - 1; ++i){
				int y = prvec[i + 1] - prvec[i];
				if(y < mindis) mindis = y, minpos = i;
				if(y > maxdis) maxdis = y, maxpos = i;
			} 
			cout << prvec[minpos] << "," << prvec[minpos + 1] << " are closest, "
			     << prvec[maxpos] << "," << prvec[maxpos + 1] << " are most distant." << endl;
		}
	}
	return 0;
}