POJ 2689 Prime Distance【区间素数筛】

题目

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 ) (1\le L < U \le 2,147,483,647) (1L<U2,147,483,647), and you are to find the two adjacent primes C 1 a n d C 2 ( L ≤ C 1 < C 2 ≤ U ) C_1 and C_2 (L\le C1< C2\le U) C1andC2(LC1<C2U) that are closest (i.e. C 2 − C 1 C_2-C_1 C2C1 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 D 1 a n d D 2 ( L ≤ D 1 < D 2 ≤ U ) D_1 and D_2 (L\le D1< D2\le U) D1andD2(LD1<D2U) where D 1 a n d D 2 D_1 and D_2 D1andD2 are as distant from each other as possible (again choosing the first pair if there is a tie).

题目大意:求解在一定范围内,任意区间中的所有相邻素数中差值最大与差值最小的两组素数。

输入

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.

输出

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.

输入样例

2 17
14 17

输出样例

2,3 are closest, 7,11 are most distant.
There are no adjacent primes.

题目分析

有分析可知,此题可计算出当前指定区间中所有的素数,判定区间中素数个数是否包含两个及以上。若无,则输出不存在,若有,则逐个计算相邻素数间的差值。
在求解指定区间[m,n]中的素数时,因为所求范围过大,采取暴力枚举的方法效率过低,不适宜采用。
由此可通过先行求解 n \sqrt{n} n 中所有的素数,用此范围中的素数乘以相应的倍数来筛去所求区间中的合数,即采用欧拉筛相同的原理进行筛选素数。

关于欧拉筛,请戳这里

应用知识点

此处重点说明区间筛数

int isprime[1000005];//代表求解区间每个数的状态
int prime[100005];//已经求出来的,存放根号n范围内所有素数
int ans[100005];//存放求解区间中所有素数
int cnt = 0;//统计根号n中的素数个数
int right,left;//左右区间范围
cin >> left >> right;
memset(isprime,1,sizeof(isprime));//标记范围内数全为素数
if(left==1) isprime[1] = 0;//假如区间左端点为1,1不是素数
for(int i = 1;i<=cnt;++i)
//对已经求解出的素数依次遍历,筛去区间中以此素数为最小质因数的合数
	for(int j = max(prime[i],(left-1)/prime[i]+1);j<=right/prime[i];++j)
	//max函数意在找出prime[i]能筛去的在区间范围内最小的合数
	//本质上是通过j*prime[i]来筛去合数
		isprime[prime[i]*j-left+1]=0;//标记该合数
int tol = 0;//统计区间范围内的素数个数
for(int i = 1;i<=(right-left+1);++i){
//遍历区间,存储素数表
	if(isprime[i] != 0) ans[++tol] = left+i-1;
}

代码

#include<iostream>
#include<cstring>
using namespace std;

int isprime[1000005];
int prime[100005];
int ans[100005];
int cnt = 0;
void getprime(int n){//欧拉筛
	memset(isprime,1,sizeof(isprime));
	isprime[1] = 0;
	for(int i = 2;i<=n;++i){
		if(isprime[i]) prime[++cnt]=i;
		for(int j = 1;j<=cnt&&(i*prime[j])<=n;++j){
			isprime[i*prime[j]] = 0;
			if(i%prime[j]==0) break;
		}
	}
}

int main()
{
	getprime(1<<16);//取最大范围一次筛选,保存结果
	int right,left;
	while(scanf("%d %d",&left,&right)!=EOF){
		memset(isprime,1,sizeof(isprime));
		if(left==1) isprime[1] = 0;
		for(int i = 1;i<=cnt;++i)
			for(int j = max(prime[i],(left-1)/prime[i]+1);j<=right/prime[i];++j)
				isprime[prime[i]*j-left+1]=0;
		int tol = 0;
		for(int i = 1;i<=(right-left+1);++i){
			if(isprime[i] != 0) ans[++tol] = left+i-1;
		}
		int tm,tl,min = 1000000,lo = 0;
		if(tol < 2) cout <<"There are no adjacent primes."<<endl;
		else{
			for(int i = 1;i<=tol - 1;++i){//最小
				if(min > (ans[i+1] - ans[i])){
					min = ans[i+1]-ans[i];
					tm = i;
				}
				if(lo < (ans[i+1] - ans[i])){//最大
					lo = ans[i+1]-ans[i];
					tl = i;
				}
			}
			cout<<ans[tm]<<","<<ans[tm+1]<<" are closest, "
			cout<<ans[tl]<<","<<ans[tl+1]<<" are most distant."<<endl;
		}
	}
	return 0;
}

运行结果

在这里插入图片描述

题目链接

POJ 2689

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

registor11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值