POJ 2689 Prime Distance (经典素数筛选)

本文介绍了一种在给定大区间内快速找出相邻素数的方法,通过预先筛选出部分素数并利用这些素数对询问区间进行二次筛选,有效解决了区间范围大、时间与空间资源限制的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处,谢谢http://blog.youkuaiyun.com/ACM_cxlove?viewmode=contents by---cxlove

POJ 2689 Prime Distance

http://poj.org/problem?id=2689

区间范围很大,2^31左右,不可能筛选出所有素数,时间和空间都不允许。

但是可以发现询问的区间不是很大,相关是在10^6,这就是本题的突破口了。

首先做一次素数筛选,筛选出sqrt(区间上界)的素数,然后用这些,对询问区间进行筛选,空间也只需要10^6。

注意中间会溢出int

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 100005
#define inf  1<<30
#define MOD 9973
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
bool flag[100005];
int prime[100005],cnt=0;
//先打出sqrt(上界)的素数表
void Prime(){
	for(int i=2;i<=47000;i++){
		if(flag[i])
			continue;
		prime[cnt++]=i;
		for(int j=2;j*i<=47000;j++)
			flag[i*j]=true;
	}
}
bool isprime[1000005];
int a[1000005],c;
int main(){
	int l,r;
	Prime();
	while(scanf("%d%d",&l,&r)!=EOF){
		memset(isprime,true,sizeof(isprime));
		if(l==1) l=2;
		//利用之前的素数,进行二次筛选,注意防溢出
		for(int i=0;i<cnt&&(LL)prime[i]*prime[i]<=r;i++){
			int s=l/prime[i]+(l%prime[i]>0);
			if(s==1)
				s=2;
			//不能从1开始,不然就把素数给判成合数了
			for(int j=s;(LL)j*prime[i]<=r;j++)
				if((LL)j*prime[i]>=l)
			    	isprime[j*prime[i]-l]=false;
		}
		c=0;
		for(int i=0;i<=r-l;i++)
			if(isprime[i])
				a[c++]=i+l;
		//少于两个素数
		if(c<2){
			puts("There are no adjacent primes.");
			continue;
		}
		int x1=0,x2=0,y1=0,y2=inf;
		for(int i=1;i<c;i++){
			if(a[i]-a[i-1]>x2-x1){
				x1=a[i-1];
				x2=a[i];
			}
			if(a[i]-a[i-1]<y2-y1){
				y1=a[i-1];
				y2=a[i];
			}
		}
		printf("%d,%d are closest, %d,%d are most distant.\n",y1,y2,x1,x2);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值