1. 问题描述:
哥德巴赫猜想的内容如下:
任意一个大于 4 的偶数都可以拆成两个奇素数之和。例如:
8=3+5
20=3+17=7+13
42=5+37=11+31=13+29=19+23
现在,你的任务是验证所有小于一百万的偶数能否满足哥德巴赫猜想。
输入格式
输入包含多组数据。每组数据占一行,包含一个偶数 n。读入以 0 结束。
输出格式
对于每组数据,输出形如 n = a + b,其中 a,b 是奇素数。若有多组满足条件的 a,b,输出 b−a 最大的一组。若无解,输出 Goldbach's conjecture is wrong.。
数据范围
6 ≤ n < 10 ^ 6
输入样例:
8
20
42
0
输出样例:
8 = 3 + 5
20 = 3 + 17
42 = 5 + 37
来源:https://www.acwing.com/problem/content/description/1294/
2. 思路分析:
对于数论的相关问题主要是卡两点:① 时间复杂度;② int,long long的存储范围;并且很多时候需要取模,我们需要注意什么情况下可以取模才不会出现问题。对于这道题目来说我们需要筛选出1~n的质数,常见的筛质数有两大类方法:① 线性筛 ② 埃氏筛;埃氏筛法在写的时候并不是用得很多但是思想会比较重要,用得比较多的是线性筛法。对于这道题目来说如果直接使用试除法来判断一个数字是否是质数的方法来解决的时间复杂度会有点高,首先第一层循环需要遍历n次,然后判断a和b是否都是质数,时间复杂度为O(n√n) = 10 ^ 9,我们需要想一种比较低的时间复杂度的方法来解决这个问题,可以先使用线性筛法筛选出1~n的所有质数,这一步是预处理的操作,然后第一层循环枚举a,b = n - a,因为循环的是质数,所以a肯定是质数,所以判断b是否是质数即可,如果b是质数,而且a是最小的,所以b - a的差是最大的满足题目要求直接输入break即可,通过预处理筛选出所有的质数时间复杂度会降低很多,背熟悉线性筛的模板直接默写即可。
3. 代码如下:
from typing import List
class Solution:
# 线性筛求解1~n中的所有质数
def init(self, n: int, primes: List[int], st: List[int]):
count = 0
for i in range(2, n):
if st[i] == 0:
primes[count] = i
count += 1
j = 0
while primes[j] * i < n:
st[primes[j] * i] = 1
if i % primes[j] == 0:
break
j += 1
def process(self):
N = 10 ** 6
primes, st = [0] * N, [0] * N
self.init(N, primes, st)
while True:
n = int(input())
if n == 0: break
# 因为是奇素数所以需要下标从1开始
i = 1
while True:
a = primes[i]
b = n - a
if st[b] == 0:
print("{:} = {:} + {:}".format(n, a, b))
break
i += 1
if __name__ == '__main__':
Solution().process()