欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

L. Ultra Weak Goldbach's Conjecture(数论(大素数判断)+素数筛+哥德巴赫猜想)

程序员文章站 2022-07-14 09:45:54
...

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位,那么我只需要构造出一个偶数出来就行);
意思就是这个意思:
L. Ultra Weak Goldbach's Conjecture(数论(大素数判断)+素数筛+哥德巴赫猜想)
这样就使得最后两个素数的和为偶数;
因为我输入的数 要么为奇数要么为偶数;
所以
1.如果我输入的数为奇数,那么我就可以这样构造使得上面最后两个数的和为偶数:
L. Ultra Weak Goldbach's Conjecture(数论(大素数判断)+素数筛+哥德巴赫猜想)
因为奇数-奇数就为偶数;
2.如果我输入的数为偶数,那么我就可以这样构造使得上面最后两个数的和为偶数:
L. Ultra Weak Goldbach's Conjecture(数论(大素数判断)+素数筛+哥德巴赫猜想)
因为偶数-偶数就是偶数;
所以构造完成;
然后就是最简单的一步了,怎么去找两个素数使得他们成为最后两个数;
其实这道题我在写的时候也很无语,直接暴力?我看了一下,这个东东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;
}