Acwing196. 质数距离

给定两个整数 LL 和 UU,你需要在闭区间 [L,U][L,U] 内找到距离最接近的两个相邻质数 C1C1 和 C2C2(即 C2−C1C2−C1 是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。

同时,你还需要找到距离最远的两个相邻质数 D1D1 和 D2D2(即 D1−D2D1−D2 是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。

输入格式

每行输入两个整数 LL 和 UU,其中 LL 和 UU 的差值不会超过 106106。

输出格式

对于每个 LL 和 UU,输出一个结果,结果占一行。

结果包括距离最近的相邻质数对和距离最远的相邻质数对。(具体格式参照样例)

如果 LL 和 UU 之间不存在质数对,则输出 There are no adjacent primes.

数据范围

1≤L<U≤231−11≤L<U≤231−1

输入样例:

2 17
14 17

输出样例:

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

题意分析:
    找到给定区间所有相邻素数的最近距离和最远距离
     
解题思路: 

  1.  因为题目所给数据量太大,利用线性筛法也不能将所给的素数全部晒出来,所以利用 每一个合数都是一个素数的若干倍数 
  2.  首先找到50000内的所有素数(朴素筛法就可以完成)
  3.  枚举每一个素数,所枚举素数的任何倍数都应该从所给区间里面去除
            令枚举素数为p,首先要找到p的开始位置,p有可能在所给区间内,也有可能在所给区间外,这时候就需要找到一个开始的 p
                    这里用到一个公式:(l + r -1)/ p * p 就可以轻松得到这个 p 
            将所有倍数标记去除
  4.  找到区间内相距最近或者最远的素数
            有可能没有素数
                   输出没有
            有素数
                   利用两个标记 minp maxp
                          如果前一个素数与后一个素数(primes[i + 1] - primes[i])的距离小于 primes[minp + 1] - primes[minp] ,就将minp = i;
                          如果(primes[i + 1] - primes[i])的距离大于 primes[maxp + 1] - primes[maxp], 将maxp = i; 
  5.  最后按格式输出

易错分析:

  •  在找起点p时
            有可能p在题目给定的区间,因而我们不能直接将p筛掉,因该让起点为2 * p
            因为给定的范围太大,所有应该用long long 定义     
  • 将所有质数存起来时
            要判定 1 既不是素数也不是合数
            另外储存的是 i + l 而不是 i  

实现代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

#define ll long long
const int N = 1e6;

int cnt;
int primes[N];
bool st[N];
// 线性筛法 
void GetPrimes(int n) 
{
	memset(st, false, sizeof st);	
	cnt = 0;
    for(int i = 2; i <= n; i ++)
    {
        if(!st[i]) 
            primes[cnt++] = i;
        for(int j = 0; primes[j] <= n / i; j ++)
		{
			st[primes[j] * i] = true;
			if(i % primes[j] == 0) break;	
		} 
    }
}

int main()
{
	ll l, r;
	while(cin >> l >> r)
	{
	
		GetPrimes(50000);
		
	//	for(int i = 0; i < cnt; i ++)
	//		cout << primes[i] << endl;
	
		memset(st, false, sizeof st);
		for(int i = 0; i < cnt; i ++)
		{
			int p = primes[i]; 
			for(ll j = max((l + p - 1) / p * p, 2ll * p); j <= r; j += p)
				st[j - l] = true; //因为 l 不一定是从0 开始的, 所以要减去偏移量 
		}
		
		cnt = 0;
		for(int i = 0; i <= r - l; i ++)
		{
			if(!st[i] && i + l > 1) //1既不是质数也不是合数 
				primes[cnt ++] = i + l;
		}
		
		if(cnt < 2) puts("There are no adjacent primes.");
		else
		{	
			int minp = 0, maxp = 0;
			for(int i = 0; i + 1 < cnt; i ++)
			{
				int d = primes[i + 1] - primes[i];
				if(d < primes[minp + 1] - primes[minp]) minp = i;
				if(d > primes[maxp + 1] - primes[maxp])	maxp = i;
			} 
			printf("%d,%d are closest, %d,%d are most distant.\n", primes[minp], primes[minp + 1], primes[maxp], primes[maxp + 1]);
		}		
		
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值