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; }