Goldbach 2018 ACM-ICPC

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

这道题大致就是给你一个2到2∧63的(unsigned long long)数(n),要你在一秒内判断这个数能分成哪两个质数的和,由于N以内的素数个数近似为n/ln(n)个,这对于一个很大的数意味着他一定可以拆成一个10e6以内的素数(m)与另一个极大的素数,10e6以内的素数打表就好了,关键问题是如何快速判断一个unsigned long long 型整数(n-m)是否是素数,常规的算法最少也要几秒,效率不够,这里就用到了米勒罗宾素数判定法,但这个算法并不是严格正确的,但他判错的概率极低,所以还是相当有效的。

上代码:

#include <bits/stdc++.h>
using namespace std;
const int times = 20;
int number = 0;

map<unsigned long long, int>m;
unsigned long long Random(unsigned long long n ) 
{
    return ((double)rand( ) / RAND_MAX*n + 0.5);
}

unsigned long long q_mul(unsigned long long a,unsigned long long b,unsigned long long mod ) 
{
    unsigned long long ans = 0;
    while(b)
    {
        if(b & 1)
        {
            b--;
            ans =(ans+ a)%mod;
        }
        b /= 2;
        a = (a + a) % mod;

    }
    return ans;
}

unsigned long long q_pow(unsigned long long a,unsigned long long b,unsigned long long mod ) 
{
    long long ans = 1;
    while(b)
    {
        if(b & 1)
        {
            ans = q_mul( ans, a, mod );
        }
        b /= 2;
        a = q_mul( a, a, mod );
    }
    return ans;
}

bool witness(unsigned long long a,unsigned long long n )
{
    unsigned long long tem = n - 1;
    int j = 0;
    while(tem % 2 == 0)
    {
        tem /= 2;
        j++;
    }

    unsigned long long x = q_pow( a, tem, n );
    if(x == 1 || x == n - 1) return true;
    while(j--)
    {
        x = q_mul( x, x, n );
        if(x == n - 1) return true;
    }
    return false;
}

bool miller_rabin(unsigned long long n )  
{

    if(n == 2)
        return true;
    if(n < 2 || n % 2 == 0)
        return false;
    for(int i = 1; i <= times; i++)  
    {
        long long a = Random( n - 2 ) + 1;
        if(!witness( a, n ))
            return false;
    }
    return true;
}
const int N=100001;
bool nop[N];
int pri[N],pn;
void innit()
{
    pn=0;
    nop[1]=1;
    for(int i=2; i<N; i++)
    {
        if(nop[i]==false)
        {
            pri[pn++]=i;
        }
        for(int j=0; j<pn&&pri[j]*i<N; j++)
        {
            nop[pri[j]*i]=true;
            if(i%pri[j]==0) break;
        }
    }
}
int main()
{
    innit();
    int t;
    unsigned long long n,m;
    //cin>>t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        int flg=0;
        for(int i=0; pri[i]<n&&i<N; i++)
        {
            m=n-pri[i];
            if(miller_rabin(m))
            {
                flg=1;
                break;
            }
        }
        if(flg==1)
            printf("%lld %lld\n",n-m,m);
        //cout<<n-m<<' '<<m<<endl;
    }
    return 0;
}

 

posted @ 2018-04-23 22:01  shadowlink  阅读(204)  评论(0编辑  收藏  举报