题意:题意很简单,就是让你验证哥德巴赫猜想——一个大于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;
}
}
}
}