数论——区间筛质数

数论——区间筛质数

引入

质数讲解中我们提到可以使用线性筛,去筛选1~n之间的质数,时间复杂度是线性的。对于一段区间[l, r],我们可以依据这个思路,筛1~r的质数,然后通过二分法,找到左边界。然而这样做是有缺陷的。比如当我们r的范围很大时,这要的线性筛法会超时。最好的办法是,直接筛[l, r]之间的数。
下面具体讲一下实现思路。

思路

要想筛[l, r]之间的质数,借鉴筛质数的思路,我们需要知道[l, r]的质因数,通过埃氏筛法将[l, r]中所有相关的合数全部筛掉。一个合数x的最小质因子一定小于等于 x \sqrt{x} x ,证明略。我们每次只需要用这个最小质因子,将所有相关的合数筛掉即可。
下面我们来看一道例题。

质数距离

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

输入格式
每行输入两个整数 L
和 U,其中 L 和 U 的差值不会超过 10^6。

输出格式
对于每个 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.

代码

sqrt(2 ** 31 -1)
46340.950001051984
from math import ceil

N = 1000010
st = [False] * N
primes = []
# 筛质数模板
def init(n) :
	for i in range(2, n + 1) :
		if not st[i] :
			primes.append(i)
		for j in primes :
			if i * j > n :
				break
			st[i * j] = True
			if i % j == 0 : break

try :
	while True :
		l, r = map(int, input().split())
		primes = []
		st = [False] * N
		init(50010)
		st = [False] * N
		for i in primes : # 筛l~r之间的质数
			j = max(ceil(l / i), 2) * i
			while j <= r :
				st[j - l] = True # 筛掉合数
				j += i
		primes = []
		for i in range(r - l + 1) :
			if not st[i] and i + l >= 2 :
				primes.append(i + l)
		length = len(primes)
		if length < 2 :
			print("There are no adjacent primes.")
			continue
		minn, maxx = 10000010, 0
		minl, minr, maxl, maxr = 0, 0, 0, 0
		for i in range(length - 1) :
			if minn > primes[i + 1] - primes[i] :
				minn = primes[i + 1] - primes[i]
				minl, minr = primes[i], primes[i + 1]
			if maxx < primes[i + 1] - primes[i] :
				maxx = primes[i + 1] - primes[i]
				maxl, maxr = primes[i], primes[i + 1]
		print(f"{minl},{minr} are closest, {maxl},{maxr} are most distant.")    
except : pass

总结

对于数论问题一定要发掘题目中的具体关系。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值