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