题目

歌德巴赫猜想的一种计算验证:对每个大于 4 的偶数 (n),存在素数 (a,b) 使 (a+b=n)。本题额外要求:

输入:多行,每行一个偶数 (n)((4 < n \le 20000))
输出:对应的 a b

样例:

输入          输出
8      ->     3 5
10     ->     5 5
1000   ->     491 509

关键观察

在 (a+b=n) 且 (a\le b) 时,(b=n-a),乘积 (a(n-a)) 是关于 (a) 的二次函数,对称轴在 (a=n/2)。因此 (a) 越靠近 (n/2),乘积越大

策略:从 (a=\lfloor n/2 \rfloor) 向下枚举,找到的第一对「(a) 与 (n-a) 都是素数」就是答案。

参考实现

#include <cstdio>
#include <cmath>

bool isPrime(int x) {
    if (x < 2) return false;
    if (x == 2) return true;
    if (x % 2 == 0) return false;
    int lim = (int)std::sqrt((double)x);
    for (int i = 3; i <= lim; i += 2)
        if (x % i == 0) return false;
    return true;
}

int main() {
    int n;
    while (scanf("%d", &n) == 1) {
        for (int a = n / 2; a >= 2; --a) {
            int b = n - a;
            if (a > b) continue;
            if (isPrime(a) && isPrime(b)) {
                printf("%d %d\n", a, b);
                break;
            }
        }
    }
    return 0;
}

比旧代码更干净:不必手写「偶数就 --」的别扭循环,从中点递减即可。

复杂度

预筛优化(可选)

// 埃氏筛预处理 isPrime[0..N]

多组查询时收益明显。

小结

本题考的不是证明歌德巴赫,而是:约束下的搜索起点选择。乘积最大 ⇒ 从 (n/2) 往下找第一对素数解。写出正确的 isPrime 边界后,代码非常短。

正确性直觉

对偶数 (n),从 (a=n/2) 向下找素数对,等价于在约束 (a+b=n) 下最大化 (a(n-a))。二次函数在中点取最大,故「中点往下第一对素数」即所求。

小优化

和真正的猜想

本题是编程验证给定范围内的拆分,不是证明歌德巴赫猜想本身。数学上偶数哥德巴赫仍是著名问题;工程上我们只在有限 (n) 上找构造。