2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 B题Goldbach

题意:题意很简单,就是让你验证哥德巴赫猜想——一个大于2的偶数可以分解成两个素数之和。但数据量有点大2^63。

思路:预处理一个10^6以内的素数表,然后循环判断n-prime[i]是否为素数,如果为素数则打印退出循环即可。当然,这不可能用普通的判素数的方法,这里用到了一个Miller-Rabin质数测试。我觉得我能理有限也讲不清楚,所以我贴hihocoder上的讲(ti)解(mu),讲得很详细。地址如下:http://hihocoder.com/problemset/problem/1287。不过这里要注意进行乘法的时候可能会出现超long long而导致超时,我在这个坑搞了好久。把long long 改成unsigned long long 就好了。

AC代码:

#include<stdio.h>
#include<string.h>
#include <bits/stdc++.h>
#include<algorithm>
using namespace std;
#define ll long long
ll prime[1000000];
bool vis[1000000];
int cnt;
void find()
{
    for(int i=4;i<1000000;i+=2) vis[i]=1;
    prime[cnt++]=2;
    for(int i=3;i<1000000;i++)
    {
        if(!vis[i])
        {
            prime[cnt++]=(ll)i;
            for(int j=i+i;j<1000000;j+=i)
            vis[j]=1;
        }
    }
}
ll add(unsigned ll a,unsigned ll b,unsigned ll n)
{
    ll ans=0; a%=n;
    while(b)
    {
        if(b&1)
        {
            //ans=((ans%n)+(a%n))%n;
            ans+=a;
            if(ans>n) ans-=n;
        }
        b>>=1;
        //a=((a%n)+(a%n))%n;
        a<<=1;
        if(a>n) a-=n;
    }
    return ans;
}
ll quick(ll a,ll u,ll n)
{
    unsigned ll ans=1; a%=n;
    while(u)
    {
       // printf("sa");
        if(u&1) {ans=add(ans,a,n);}
        a = add(a,a,n);
        u/=2;
    }
    return ans;
}
bool MR(ll n)
{
    if(n==2) return true;
    if(n<2 || !(n&1)) return false;
    unsigned ll u=n-1;
    int k=0;
    while(!(u&1)) u>>=1,k++;

    srand(time(NULL));
    for(int i=0;i<10;i++)
    {
        unsigned ll a=rand()%(n-1)+1;
        //printf("%llu\n",u);
        unsigned ll x=quick(a,u,n)%n;
        //printf("\nbd");
        unsigned ll y=0;
        //printf("%llu\n",x);
        for(int j=0;j<k;j++)
        {
            y=add(x,x,n);
            if(y==1 && x!=1 && x!=(n-1))
            return false;
            x=y;
        }
        if(y!=1) return false;
    }
    return true;
}
int main()
{
    find();
    int cases;scanf("%d",&cases);
    while(cases--)
    {
        unsigned ll n; scanf("%lld",&n);
        for(int i=0;i<cnt;i++)
        {
            if(MR(n-prime[i]))
            {
                printf("%lld %lld\n",prime[i],n-prime[i]);
                break;
            }
        }
        //printf("sa");
    }
}//9223372036854775808

这里多说一句:其实用Java的话...什么MR测素数,完全不用管,素数打表也不用,n/2,一次减2的测都能过,可以说是很服气的了。这里也贴个Java的AC代码:

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;

import java.io.*;
public class Main{
	
	public static void main(String[] args){
		Scanner cin = new Scanner(System.in);
		int cases = cin.nextInt();
		while((cases--) > 0){
			long n = cin.nextLong();
			if(n==4){
				System.out.println("2 2");
				continue;
			}
			long y = n/2;
			if((y&1)==0) y++;
			while(y>0){
				long x=n-y;
				if(BigInteger.valueOf(x).isProbablePrime(100)&&BigInteger.valueOf(y).isProbablePrime(100)){
					System.out.println(x+" "+y);
					break;
				}
				y-=2;
			}
		}
		
	}
}


猜你喜欢

转载自blog.csdn.net/m0_37514283/article/details/80067332