L. Ultra Weak Goldbach's Conjecture(数论(大素数判断)+素数筛+哥德巴赫猜想)
题意:叫我们去证明这个题的猜想,通过输出答案来证明;
首先需要知道著名的哥德巴赫猜想:任意一个大于2的偶数,均可以有两个素数的和表示出来!!
然而这个题猜想是:对于大于11的数,他能由6个素数的和组成,然后让我们找出这6个素数,其中可以是相同的素数;
这里需要用到的数论常识结论:
1.对于素数除了2,其余素数均为奇数;
2.奇数个奇数相加等于奇数;
3.奇数+或者-奇数结果为偶数;
4.奇数+或者-偶数结果为奇数;
5.偶数+或者-偶数结果为偶数;
6.偶数+或者-奇数结果为奇数;
所以这个题很明显题目都告诉我们了,对于<=11的数是肯定不能由6个素数的和组成的;
但是对于>11的数,怎么办呢?
因为他题目说输出任意一个答案就可以了;
那可不可以这样想?
因为素数2比较特殊,我能不能把找6个素数的和转化为找2个素数的和呢?
所以有了这个想法之后我就可以去试着构造4个已知的数是的我最后只需要找两个素数的和就可以了;
那么怎么构造呢?
这就需要思维了(但是如果你知道除了2,其他素数都是奇数的时候,你应该能想到构造出使得最后两个数的和为偶数,因为一共有6位,那么我只需要构造出一个偶数出来就行);
意思就是这个意思:
这样就使得最后两个素数的和为偶数;
因为我输入的数 要么为奇数要么为偶数;
所以
1.如果我输入的数为奇数,那么我就可以这样构造使得上面最后两个数的和为偶数:
因为奇数-奇数就为偶数;
2.如果我输入的数为偶数,那么我就可以这样构造使得上面最后两个数的和为偶数:
因为偶数-偶数就是偶数;
所以构造完成;
然后就是最简单的一步了,怎么去找两个素数使得他们成为最后两个数;
其实这道题我在写的时候也很无语,直接暴力?我看了一下,这个东东1e12,这个东西超时?
后面我又想了一下对于一个数量级以内的数,肯定会有一个素数吧!!!
带着这个猜想我打了1e6的素数表,然后以当前这个素数为基准,去看n-8-pri[i]或者n-9-pri[i]是不是素数。居然AC了…
这也许就是缘分吧(应该是猜想对滴才AC!!!)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//素数判定
ll mod_mul(ll x, ll y, ll mod) // 乘法防止溢出, 如果p * p不爆ll的话可以直接乘; O(1)乘法或者转化成二进制加法
{
return (x * y - (ll)(x / (long double)mod * y + 1e-3) * mod + mod) % mod;
}
long long pow_mod(long long a, long long b, long long n) {
long long res = 1;
while(b) {
if(b & 1)
res = mod_mul(res, a, n);
a = mod_mul(a, a, n);
b >>= 1;
}
return res;
}
bool test(ll n,ll a,ll d)
{
if(n==2) return true;
if(n==a) return false;
if(!(n&1)) return false;
while(!(d&1)) d>>=1;
ll t = pow_mod(a,d,n);
while(d!=n-1&&t!=n-1&&t!=1){
t = mod_mul(t,t,n);//下面介绍防止溢出的办法,对应数据量为10^18次方;
d<<=1;
}
return t == n-1||(d&1)==1;//要么t能变成n-1,要么一开始t就等于1
}
bool Miller_Rabin(ll n)//判断n是不是素数
{
int a[] = {2,3,5,233,331};//或者自己生成[2,N-1]以内的随机数rand()%(n-2)+2
for(int i = 0; i < 5; ++i){
if(n==a[i]) return true;
if(!test(n,a[i],n-1)) return false;
}
return true;
}
//素数筛选
const ll N = 1e6 + 10;
ll pri[700010], k;//k记录素数的个数这里的素数是从下标为0开始的
bool Isprime[N];//这个除了辅助筛素数,也可以用来判断是不是素数if(Isprime[n])) n为素数;
void prime()
{
k = 0;
memset(Isprime, true, sizeof(Isprime));
Isprime[1] = false;
for(ll i = 2 ; i < N ; i++)
{
if(Isprime[i])
{
pri[k++] = i;
for(ll j = 2 ; i * j < N ;j++)
Isprime[i * j] = false;
}
}
}
int main(){
prime();
ll T;
scanf("%lld",&T);
ll g=1;
while(T--){
ll n;
scanf("%lld",&n);
printf("Case %lld: ",g++);
if(n<=11)puts("IMPOSSIBLE");//<=11的数,不可能成立,根据题目可以知道
else{
if(n&1){//输入的数为奇数
n=n-9;//变为偶数
printf("2 2 2 3 ");
for(int i=0;i<k;i++){
if(Miller_Rabin(n-pri[i])){
printf("%lld %lld\n",pri[i],n-pri[i]);
break;
}
}
}else{//为偶数
n=n-8;//变为偶数
printf("2 2 2 2 ");
for(int i=0;i<k;i++){
if(Miller_Rabin(n-pri[i])){
printf("%lld %lld\n",pri[i],n-pri[i]);
break;
}
}
}
}
}
return 0;
}