henuoj 1166 TonyStark with Prime(Hard Edition) 哥德巴赫猜想
哥德巴赫猜想:任何一个大于2的偶数能拆成两个素数之和
正好可以用在本题
(题目描述中说的任何一个大于3的数能拆分乘两个素数和是错误的,举个例子,11,如果想拆分成两个数的和必须是一个奇数一个偶数,偶数素数只有2,奇数只能是9,显然不成立)
本题目中给定一个数字 n ,(n <= 1e12),求这个数字能否由四个素数组成,如果能,输出所有方案中的任何一个,如果不能输出3000.
首先,最小的素数是2,所以2 * 4 = 8,要想组成最小是8,小于8无法完成输出3000,对于大于8的都可以。
原因:如果大于8是一个偶数,拆分成两个偶数,利用哥德巴赫猜想可以明显看出可以,如果是奇数,先拆分出一个2一个3,剩下的又是一个偶数拆分成两个素数,很明显可以。
我们怎么求满足条件的数字呢?
首先预处理一个区间内的所有素数(埃式筛),对输入的数字 n 进行判断,如果小于8就输出3000,否则判断奇偶性,如果是偶数,就把偶数拆分成为两个偶数 t1 , t2 ,对每一个偶数,循环遍历刚刚区间内的全部数字,如果有一个 数满足 (t1 - i)是素数,则记录下来跳出循环,另外一个偶数同样操作,如果是奇数,首先得到两个数2 和 3,然后 n -= 5,回到刚刚的一个步骤求解即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
ll n;
ll v[1000000];
void pre_work(){
v[0] = -1;
v[1] = -1;
for (int i = 2; i < 1000000; i++){
if(v[i] != 0)continue;
v[i] = 1;
for (int j = 2; j * i < 1000000; j++){
v[i * j] = -1;
}
}
}
int is(ll num){
if(num == 1)return 0;
if(num == 0)return 0;
if(num == 2)return 1;
ll sq = sqrt(num);
for (ll i = 2; i <= sq; i++){
if(num % i == 0)return 0;
}
return 1;
}
int main()
{
vector<ll> prime;
pre_work();
for (int i = 2; i < 1000000; i++)if(v[i] == 1)prime.push_back(i);
while (cin >> n){
if(n < 8){
cout << "3000" << endl;
continue;
}
if(n & 1){
ll a, b, c, d;
a = 2;
b = 3;
n -= 5;
for (ll i : prime){
if(is(n - i)){
c = i;
d = n - i;
break;
}
}
printf("%lld %lld %lld %lld\n", a, b, c, d);
}
else{
ll a, b, c, d;
ll t1 = n / 2;
ll t2 = t1;
if(t1 & 1){
t1++;
t2--;
}
for (ll i : prime){
if(is(t1 - i)){
a = i;
b = t1 - i;
break;
}
}
for (ll i : prime){
if(is(t2 - i)){
c = i;
d = t2 - i;
break;
}
}
printf("%lld %lld %lld %lld\n", a, b, c, d);
}
}
return 0;
}
本文来自博客园,作者:correct,转载请注明原文链接:https://www.cnblogs.com/correct/p/12862073.html

浙公网安备 33010602011771号