Description:
Goldbach's conjecture is one of the oldest and best-known unsolved problems in number theory and all of mathematics. It states:
Every even integer greater than 2 can be expressed as the sum of two primes.
The actual verification of the Goldbach conjecture shows that even numbers below at least 1e14 can be expressed as a sum of two prime numbers.
Many times, there are more than one way to represent even numbers as two prime numbers.
For example, 18=5+13=7+11, 64=3+61=5+59=11+53=17+47=23+41, etc.
Now this problem is asking you to divide a postive even integer n (2<n<2^63) into two prime numbers.
Although a certain scope of the problem has not been strictly proved the correctness of Goldbach's conjecture, we still hope that you can solve it.
If you find that an even number of Goldbach conjectures are not true, then this question will be wrong, but we would like to congratulate you on solving this math problem that has plagued humanity for hundreds of years.
Input:
The first line of input is a T means the number of the cases.
Next T lines, each line is a postive even integer n (2<n<2^63).
Output:
The output is also T lines, each line is two number we asked for.
T is about 100.
本题答案不唯一,符合要求的答案均正确
样例输入
1
8
样例输出
3 5
题目来源
2018 ACM-ICPC 中国大学生程序设计竞赛线上赛
main.cpp
这道题看起来好像很简单。。前缀和预处理一下素数。。直接枚举就好了~
签到题争的是时间,当我真正开始写的时候我发现了一个问题。。
范围不大,但是最值太大了,足足有2^63,这么大的数别说是O2复杂度,就算是只循环O1复杂度,都压根过不去。使用筛法求素数和平方根法都无法通过测试的。
这个时候我们只能想办法来优化或者通过数学知识来简化问题~ 哥德巴赫的猜想,都听说过吧。可以试一下,一个偶数拆分的两个素数一定是一个非常大,一个非常小(不信你试试)。我们假设非常小最大是10000,这时问题就突然简化成了判断两个数是不是素数。
因为数值很大,我们考虑使用unsigned long long来存, 同时注意使用%llu
前三个函数是模板函数,大家可以保存一下,以后拿来直接用~
#include<cstdio>
#include<cstdlib>
using namespace std;
#define N 10000
typedef unsigned long long ll;
ll ModMul(ll a, ll b, ll n) { //快速积取模 a*b%n
ll ans = 0;
while(b) {
if(b & 1)
ans = (ans + a) % n;
a = (a + a) % n;
b >>= 1;
}
return ans;
}
ll ModExp(ll a, ll b, ll n) { //快速幂取模 a^b%n
ll ans = 1;
while(b) {
if(b & 1)
ans = ModMul(ans, a, n);
a = ModMul(a, a, n);
b >>= 1;
}
return ans;
}
bool miller_rabin(ll n) { //Miller-Rabin素数检测算法
ll i, j, a, x, y, t, u, s = 10;
if(n == 2)
return true;
if(n < 2 || !(n & 1))
return false;
for(t = 0, u = n - 1; !(u & 1); t++, u >>= 1); //n-1=u*2^t
for(i = 0; i < s; i++) {
a = rand() % (n - 1) + 1;
x = ModExp(a, u, n);
for(j = 0; j < t; j++) {
y = ModMul(x, x, n);
if(y == 1 && x != 1 && x != n - 1)
return false;
x = y;
}
if(x != 1)
return false;
}
return true;
}
//以上都是模板,以下为核心算法
int main()
{
ll n, t;
scanf("%llu",&t);
while(t--){
scanf("%llu", &n);
//通过数学规律可以发现第一个素数最大不超过10000
for(ll i = 1; i < N; i++){
if(miller_rabin(i) && miller_rabin(n-i)){
printf("%llu %llu\n",i, n-i);
break;
}
}
}
return 0;
}