这个题主要考察质因数分解和质数判断,构建出合理的、高效的算法还是需要动脑子的。
带有详细注释的代码如下,我相信仔细耐心阅读,便能成功理解。
下面叙述假设: a0 -> a1 -> a2(依次进行第一次操作、第二次操作)
import math
import time
#判断是否为素数
def is_prime(x):
upper_bound = int(math.sqrt(x)) + 1
for i in range(2, upper_bound):
if x % i == 0:
return False
return True
#对指定数进行质因数分解,递归实现。
def fact(n, primes):
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
primes.append(i)
fact(n // i, primes)
return
primes.append(n)
n = int(input())
#如果输入数为质数,那么打印-1。因为我们的n应该是质数的倍数,
#且必须至少为2倍(题目中说了选择一个小于 x的素数p,所以至少是2倍)。 ------①
if is_prime(n):
print(-1)
else:
primes = []
fact(n, primes) #对其质因数分解
prime_set = set(primes) #将质因数转为集合(无重复元素)
min_start = 1000001
for prime in prime_set: #遍历质因数集合
last_left_Bound = n - prime #假设第二次操作选择的是prime作为质数,那么第二次操作前的数(a1)不会小于n-prime。
# print(last_left_Bound)
#上次操作前的数字(a1)必然在左边界加1和n之间。(为什么是n?因为n可能本身就是某
#个质数的倍数,然后这次操作又选了该质数,则n不变)
for last_num in range(last_left_Bound + 1, n + 1):#对第一次操作后可能的数组遍历
if is_prime(last_num): #和①同理,不可能是质数。
continue
prime_tmp = []
fact(last_num, prime_tmp) #继续对上个数进行质因数分解
max_gap = max(prime_tmp) #找出最大的质因数作为第一次操作选择的质数,
#这样能使起始数字尽可能小
min_start = min(last_num - max_gap + 1, min_start) #更新维护最小数字
if min_start == 1000001:
print(-1)
else:
print(min_start)
比较关键的地方在于,我们在第二个内层循环分析时,要用第一次操作后可能得到的数字a1减去其最大的质因数,即第一次操作我们选择的质数是a1的最大质因数,这样才能让a0尽可能小。