质数距离(C++筛素数模板题)

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

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

输入格式

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

输出格式

对于每个 L和 U,输出一个结果,结果占一行。

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

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

数据范围

1≤L<U≤2^31−1

输入样例:
2 17
14 17
输出样例:
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.

 思路

因为这个数据范围太大,到了2^31次直接筛选一遍绝对会超时间。但是我们只需判断l-r之中的数,因此有没有一种算法能只筛出l-r之中的素数?

根据数学定理,一个合数n,必定能被一个不是自己的质数x整除,且x<=根号n。

因此我们只需将1-根号r中的所有质数筛选出来,然后将他们在l-r中的倍数删除,即可得到l-r中的质数。最后直接遍历一遍就能得到答案

#include<iostream>
#include<cstring>

using namespace std;

typedef long long LL;

const int N = 1e6 + 10; // l-r的最大距离 
LL primes[N], cnt;
bool st[N];

void init(int n)
{
	//因为st和primes有重用,因此每次开始都置为0 
	memset(st, 0, sizeof st);
	cnt = 0;
	
	for(int i = 2; i <= n; i ++)
	{
		if(!st[i]) primes[cnt ++] = i;
		
		for(int j = 0; primes[j] * i <= n; j ++)
		{
			st[primes[j] * i] = true;
			if(i % primes[j] == 0) break;
		}
	}
}

int main()
{
	int l, r;
	while(cin >> l >> r)
	{
		init(50000);	//因为st和primes有重用,因此每次开始都筛选一遍,之所以是50000,因为50000^2 = 2.5e9 > 2^31 
		memset(st, 0, sizeof st);//后面会重用
		 
		for(int i = 0; i < cnt; i ++)
		{
			LL p = primes[i];
			
			for(LL j = max(p * 2, (l + p - 1) / p * p); j <= r; j += p)// 埃式筛法j从p*2开始,(l + p - 1) / p * p是上取整,确保开始的j大于l
				st[j - l] = true; //下标有限,利用位移操作	
		} 
		
		cnt = 0;
		for(int i = 0; i <= r - l; i ++)
			if(!st[i] && i + l >= 2)//1不是质数,也没被筛过,因此要求从2开始即i + l >=2 
				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;			
			}
			
			cout << primes[minp] << ',' << primes[minp + 1] << " are closest, " <<
			primes[maxp] << ',' << primes[maxp + 1] << " are most distant." << endl;
		} 
	} 
	
	return 0;	
} 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值