Goldbach(素数判定Miller-Rabin)

题目链接:https://nanti.jisuanke.com/t/25985

题意:给定T个示例,给你一个数n,让你 的n的值可以分解成两个素数相加。

 

以前就做过这类的题,一开始以为是打表,然后发现不可行,对于2^63的数据量。

所以看了看模板书,有一个叫logN的素数判断方法,这个方法其实运用了费马小定理。

以下就是解释:要测试N是否为素数,首先将N-1分解成2^s ×d.在每次测试开始时。

先随机选一个介于[1,N-1]的整数a,如果对所有的r 属于[0,s-1]都满足

a^dmodN!=1且a^(2^r  *d)modN!=-1,则N是合数。否则,N有3/4的几率为素数。

为了提高测试的正确性,可以选择不同的a进行多次测试.

以上都是定理的原理,要是看得懂我也不会做不出来了。。。。

其实就是随机数来测试,数学老师说过,你给我一个数能很快很快地直到它是否为

素数,正确率达到百分之99。但是不能确保它是百分之100是质数。

这个题目就是要考我们这个算法,但是有一点细节要注意,因为多次调用快速幂,

要是对于数很大的时候快速幂还需要配上快速乘法才能达到效果,而且用来测试的质

数不要太多,虽然能确保它的几率大大提高,但是速度却减慢了下来,所以要少。

题目还有一个坑,2^63应该需要unsigned long long   %llu.

贴上代码,纪念我做了几个小时都没写出来的一题算法题:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn=100005;
ull prime[maxn],x[maxn],cnt;
ull qmul(ull a,ull b,ull mod){
    ull ans=0;
    while(b){
        if(b&1){
            ans=(a+ans)%mod;
        }
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
ull qpow(ull a,ull b,ull mod){
    ull ans=1;
    b%=mod;
    while(b){
        if(b&1){
            ans=qmul(ans,a,mod);
        }
        a=qmul(a,a,mod);
        b>>=1;
    }
    return ans;
}
void is_prime(){
    int t=0;
    for(int i=2;i<=maxn;i++){
        if(x[i]==0){
            prime[t++]=i;
            x[i]=1;
            for(int j=i*2;j<=maxn;j+=i){
                x[j]=2;
            }
        }
    }
    cnt=t;
}
bool test(ull n,ull a,ull d){
    if(n==2)return true;
    if(n==a)return true;
    if((n&1)==0)return false;
    while(!(d&1))d>>=1;
    ull t=qpow(a,d,n);
    while((d!=n-1)&&(t!=1)&&(t!=n-1)){
        t=(ull )(t*t)%n;
        d=d<<1;
    }
    return (t==n-1||(d&1)==1);
}
bool isprime(ull n)
{
    if(n<2) return false;
    for(int i=0;i<5;i++)
        if(!test(n,prime[i],n-1))return false;
    return true;
}
int main(){
    is_prime();
    ull T,n;
    scanf("%llu",&T);
    while(T--){
        scanf("%llu",&n);
        for(ull i=0;prime[i]<=n-1;i++){
            if(isprime(n-prime[i])){
                printf("%llu %llu\n",prime[i],n-prime[i]);
                    break;
            }
        }
    }
    return 0;
}

#include<time.h>
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define Times 3
const int N=5e6+10;
using namespace std;
typedef unsigned long long ll;
ll prime[N],cnt=0;
bool x[N];
void is_prime(){
    int t=0;
    for(ll i=2;i<N;i++){
        if(x[i]==false){
            prime[t++]=i;
            for(ll j=i*i;j<N;j+=i){
                x[j]=true;
            }
        }
    }
    cnt=t;
}
ll random(ll n){
    return (ll) ( (double)rand()/RAND_MAX *n +0.5 );
}
ll qmul(ll a,ll b,ll mod){
    ll ans=0;
    while(b>0){
        if(b&1){
            ans=(ans+a)%mod;
        }
        a=(a<<1)%mod;
        b>>=1;
    }
    return ans;
}
ll qpow(ll a,ll b,ll mod){
    ll ans=1;
    while(b){
        if(b&1){
            ans=qmul(ans,a,mod);
        }
        b>>=1;
        a=qmul(a,a,mod);
    }
    return ans;
}
bool Witness(ll a,ll n){
    ll m=n-1;
    int j=0;
    while ( !(m&1) ){
        j++;
        m>>=1;
    }
    ll x= qpow(a,m,n);
    if(x==1||x==n-1){
        return false;
    }while(j--){
        x=x*x%n;
        if(x==n-1){
            return false;
        }
    }
    return true;
}
bool miller_rabin(ll n ){
    if( n<2 )return false;
    if( n==2 )return true;
    if( !(n&1) )return false;
    for(int i=1;i<=Times;i++){
        ll a=random(n-2)+1;
        //ll a=prime[i];
        if(Witness(a,n))return false;
    }
    return true;
}
int main()
{
     is_prime();
     int T;
     scanf("%d",&T);
     while(T--){
        ll n;
        scanf("%llu",&n);
        for(ll i=0;i<cnt;i++){
            if(miller_rabin(n-prime[i])){
                printf("%llu %llu\n",prime[i],n-prime[i]);
                break;
            }
        }
     }
     return 0;
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值