题目链接:https://nanti.jisuanke.com/t/25985
题意:给定T个示例,给你一个数n,让你 的n的值可以分解成两个素数相加。
以前就做过这类的题,一开始以为是打表,然后发现不可行,对于2^63的数据量。
所以看了看模板书,有一个叫logN的素数判断方法,这个方法其实运用了费马小定理。
以下就是解释:要测试N是否为素数,首先将N-1分解成2^s ×d.在每次测试开始时。
先随机选一个介于[1,N-1]的整数a,如果对所有的r 属于[0,s-1]都满足
a^dmodN!=1且a^(2^r *d)modN!=-1,则N是合数。否则,N有3/4的几率为素数。
为了提高测试的正确性,可以选择不同的a进行多次测试.
以上都是定理的原理,要是看得懂我也不会做不出来了。。。。
其实就是随机数来测试,数学老师说过,你给我一个数能很快很快地直到它是否为
素数,正确率达到百分之99。但是不能确保它是百分之100是质数。
这个题目就是要考我们这个算法,但是有一点细节要注意,因为多次调用快速幂,
要是对于数很大的时候快速幂还需要配上快速乘法才能达到效果,而且用来测试的质
数不要太多,虽然能确保它的几率大大提高,但是速度却减慢了下来,所以要少。
题目还有一个坑,2^63应该需要unsigned long long %llu.
贴上代码,纪念我做了几个小时都没写出来的一题算法题:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn=100005;
ull prime[maxn],x[maxn],cnt;
ull qmul(ull a,ull b,ull mod){
ull ans=0;
while(b){
if(b&1){
ans=(a+ans)%mod;
}
a=(a+a)%mod;
b>>=1;
}
return ans;
}
ull qpow(ull a,ull b,ull mod){
ull ans=1;
b%=mod;
while(b){
if(b&1){
ans=qmul(ans,a,mod);
}
a=qmul(a,a,mod);
b>>=1;
}
return ans;
}
void is_prime(){
int t=0;
for(int i=2;i<=maxn;i++){
if(x[i]==0){
prime[t++]=i;
x[i]=1;
for(int j=i*2;j<=maxn;j+=i){
x[j]=2;
}
}
}
cnt=t;
}
bool test(ull n,ull a,ull d){
if(n==2)return true;
if(n==a)return true;
if((n&1)==0)return false;
while(!(d&1))d>>=1;
ull t=qpow(a,d,n);
while((d!=n-1)&&(t!=1)&&(t!=n-1)){
t=(ull )(t*t)%n;
d=d<<1;
}
return (t==n-1||(d&1)==1);
}
bool isprime(ull n)
{
if(n<2) return false;
for(int i=0;i<5;i++)
if(!test(n,prime[i],n-1))return false;
return true;
}
int main(){
is_prime();
ull T,n;
scanf("%llu",&T);
while(T--){
scanf("%llu",&n);
for(ull i=0;prime[i]<=n-1;i++){
if(isprime(n-prime[i])){
printf("%llu %llu\n",prime[i],n-prime[i]);
break;
}
}
}
return 0;
}
#include<time.h>
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define Times 3
const int N=5e6+10;
using namespace std;
typedef unsigned long long ll;
ll prime[N],cnt=0;
bool x[N];
void is_prime(){
int t=0;
for(ll i=2;i<N;i++){
if(x[i]==false){
prime[t++]=i;
for(ll j=i*i;j<N;j+=i){
x[j]=true;
}
}
}
cnt=t;
}
ll random(ll n){
return (ll) ( (double)rand()/RAND_MAX *n +0.5 );
}
ll qmul(ll a,ll b,ll mod){
ll ans=0;
while(b>0){
if(b&1){
ans=(ans+a)%mod;
}
a=(a<<1)%mod;
b>>=1;
}
return ans;
}
ll qpow(ll a,ll b,ll mod){
ll ans=1;
while(b){
if(b&1){
ans=qmul(ans,a,mod);
}
b>>=1;
a=qmul(a,a,mod);
}
return ans;
}
bool Witness(ll a,ll n){
ll m=n-1;
int j=0;
while ( !(m&1) ){
j++;
m>>=1;
}
ll x= qpow(a,m,n);
if(x==1||x==n-1){
return false;
}while(j--){
x=x*x%n;
if(x==n-1){
return false;
}
}
return true;
}
bool miller_rabin(ll n ){
if( n<2 )return false;
if( n==2 )return true;
if( !(n&1) )return false;
for(int i=1;i<=Times;i++){
ll a=random(n-2)+1;
//ll a=prime[i];
if(Witness(a,n))return false;
}
return true;
}
int main()
{
is_prime();
int T;
scanf("%d",&T);
while(T--){
ll n;
scanf("%llu",&n);
for(ll i=0;i<cnt;i++){
if(miller_rabin(n-prime[i])){
printf("%llu %llu\n",prime[i],n-prime[i]);
break;
}
}
}
return 0;
}