题目大意
题目链接
哥德巴赫猜想:任何大于 4 的偶数都可以拆成两 个奇素数之和。
比如: 8=3+5
20=3+17=7+13
42=5+37=11+31=13+29=19+23
你的任务是:验证小于10^6的数满足哥德巴赫猜想。
输出格式
对于每组数据,输出形如 n=a+b,其中 a,b 是奇素数。
若有多组满足条件的 a,b,输出 b−a 最大的一组。若无解,输出 Goldbach’s conjecture is wrong.(注意有句号)。
思路分析
看了很多题解都是打表+枚举,感觉有点憨憨的,要写还是尽自己所能吧,首先打表很容游戏想到,埃及筛法了解一下。因为素数的个数是固定的,我们一次把他们全部取出来放到一个单独的item
数组中,而不是遍历所有的数字。1000000中大概有80000左右的odd prime,一下复杂度就/10了,此时如果prime比较少,我们依然可以打表,记录所有可能的两个odd prime的组合,后面直接输出,可惜这里太大,还是得依次处理,主要有两个优化
- 每次我们在
item
数组中找到第一个大于n/2
的值,我们的查找范围不会超过这里。比如8=3+5
,我们查了3就结束了,不可能查到4以上。 - 尺取,不断的修改左右端点,第一个满足题意的odd prime对就是差值最大的对。
#include<iostream>
#include<iomanip>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX 1000005
bool prime[MAX];
vector<int> items;
int main() {
//2是偶数,不是姬素数
memset(prime, 1, sizeof(prime));
prime[0] = prime[1] = prime[2] = 0;
for (int i = 2; i < MAX; i++) {
if (prime[i])items.push_back(i);
if (i == 2 || prime[i])for (int j = 2 * i; j < MAX; j += i)prime[j] = 0;
}
int n;
while (cin >> n && n) {
//找到一个和n/2最接近的数
int pos = lower_bound(items.begin(), items.end(), n) - items.begin();
int l = 0, r = pos - 1, sign = 0;
while (r >= l) {//等于也是可以的
int sum = items[l] + items[r];
if (sum == n) {
sign = 1; break;
}
if (sum > n)r--;
else l++;
}
if (sign) printf("%d = %d + %d\n", n, items[l], items[r]);
else cout << "Goldbach's conjecture is wrong." << endl;
}
}