题目传送门:https://www.acwing.com/problem/content/198/
【题目大意】:给定两个整数L和U,你需要在闭区间[L,U]内找到距离最接近的两个相邻质数C1和C2(即C2-C1是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。同时,你还需要找到距离最远的两个相邻质数D1和D2(即D1-D2是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。如果没有满足条件的,则输出“There are no adjacent primes.”
(1≤L31−1,L和U的差值不会超过1000000).
[分析]:
看看题目便知,暴力算到1~231-1的所有质数,然后求距离,显然会超时,但是题目中L与U的差值较小,那么如果能筛出要求的区间内的所有素数,然后再线性找最大与最小相邻素数距离,时间上便有改观。
那么如何筛去指定区间的合数标出当中的素数呢?根据任何一个合数x都包含一个sqrt(x)的质因子。因此我们只需要用筛法求出2~sqrt(U)之间的所有素数,对于每个质数p,把[L,U]中能被p整除的数给标记为合数。在此我们可以枚举倍数i, 其中 ceil(L/p)<=i <=floor(U/p).最后没有被标记的数便是[L,U]内的素数。然后将相邻的两个素数两两比较,维护最大和最小距离就完成了。
#include
using namespace std;
const int MAXN =100000+6;
int L , U,cnt= 0;
bool isPrime[MAXN];
bool isNL[1000000+6];
int primeData[MAXN];
struct node{
int dis,x,y;
}temp,ansmin,ansmax;
void aishishai(int n){
memset(isPrime,true,sizeof(isPrime));
isPrime[1] = false;
for(int i = 2;i<= n ; i++){
if(isPrime[i]){
primeData[++cnt] = i;
for(int j = i; j * i <=n; j++){
isPrime[i * j] = false;
}
}
}
}
int main(){
while(cin >>L >> U){
cnt = 0;
aishishai(sqrt(U));
memset(isNL,true,sizeof(isNL));
ansmin.dis = INT_MAX;
ansmax.dis = INT_MIN;
for(int i = 1;i<= cnt; i++){
for(int j = ceil(L/primeData[i]) ; j<= floor(U/primeData[i]) ; j++){
if(j != 1&& primeData[i] * j - L>=0){
isNL[primeData[i] * j - L] = false;
mixx = max(mixx , primeData[i] * j - L);
}
}
}
if(L == 1)isNL[0] = false;
int now = 0 ;
for(long long i = L;i <= U; i++){ //之前一直有个段错误,来自于U到了INT_MAX,当i+1后为负数了,就依然满足i<=U
if(now == 0 && isNL[i -L]) {
now = i;
}
else if(now != 0 && isNL[i-L]){
temp = (node){i - now,now,i};
if(i - now < ansmin.dis){
ansmin = temp;
}
if(i - now > ansmax.dis){
ansmax = temp;
}
now = i;
}
}
if(ansmin.dis == INT_MAX && ansmax.dis== INT_MIN){
cout <<"There are no adjacent primes."<
注意段错误,数据给到最大的INT值,坑啊