poj1811

题意:给定一个64位整数,问是否为质数,如果不是,则输出其最小因子。

分析:

经典题!!

数学题

miller_rabbin素数判定。若不是,则pollard_rho分解质因子,找到最小即可。

Miller-rabin

Miller-rabin算法是一个用来快速判断一个正整数是否为素数的算法。它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1。也就是对于所有小于p的正整数a来说都应该复合a^(p-1) mod p恒等于1。那么根据逆否命题,对于一个p,我们只要举出一个a(a<p)不符合这个恒等式,则可判定p不是素数。Miller-rabin算法就是多次用不同的a来尝试p是否为素数。

但是每次尝试过程中还做了一个优化操作,以提高用少量的a检测出p不是素数的概率。这个优化叫做二次探测。它是根据一个定理:如果p是一个素数,那么对于x(0<x<p),若x^2 mod p 等于1,则x=1或p-1。逆否命题:如果对于x(0<x<p),若x^2 mod p 不等于1,则p不是素数。根据这个定理,我们要计算a^(p-1) mod p是否等于1时,可以这样计算,设p-1=(2^t) * k。我们从a^k开始,不断将其平方直到得到a^(p-1),一旦发现某次平方后mod p等于1了,那么说明符合了二次探测定理的逆否命题使用条件,立即检查x是否等于1或p-1,如果不是则可直接判定p为合数。

 

pollard-rho

这是一个用来快速对整数进行质因数分解的算法,需要与Miller-rabin共同使用。求n的质因子的基本过程是,先判断n是否为素数,如果不是则按照一个伪随机数生成过程来生成随机数序列,对于每个生成的随机数判断与n是否互质,如果互质则尝试下一个随机数。如果不互质则将其公因子记作p,递归求解p和n/p的因子。如果n是素数则直接返回n为其素因子。

至于这个随机数序列是如何生成的暂时还不能理解,而且也是有多种不同的方式。这个序列生成过程中会产生循环,遇到循环则立即退出。

 

View Code
#include <cstdio>
#include
<cstdlib>
#include
<ctime>
#include
<cstring>
#include
<iostream>
constint S=20;
usingnamespace std;

typedef
longlong LL;
#define maxn 10000

LL factor[maxn];
int tot;

LL muti_mod(LL a,LL b,LL c){
//返回(a*b) mod c,a,b,c<2^63
a%=c;
b
%=c;
LL ret
=0;
while (b){
if (b&1){
ret
+=a;
if (ret>=c) ret-=c;
}
a
<<=1;
if (a>=c) a-=c;
b
>>=1;
}
return ret;
}

LL pow_mod(LL x,LL n,LL mod){
//返回x^n mod c ,非递归版
if (n==1) return x%mod;
int bit[64],k=0;
while (n){
bit[k
++]=n&1;
n
>>=1;
}
LL ret
=1;
for (k=k-1;k>=0;k--){
ret
=muti_mod(ret,ret,mod);
if (bit[k]==1) ret=muti_mod(ret,x,mod);
}
return ret;
}

bool check(LL a,LL n,LL x,LL t){ //以a为基,n-1=x*2^t,检验n是不是合数
LL ret=pow_mod(a,x,n),last=ret;
for (int i=1;i<=t;i++){
ret
=muti_mod(ret,ret,n);
if (ret==1&& last!=1&& last!=n-1) return1;
last
=ret;
}
if (ret!=1) return1;
return0;
}

bool Miller_Rabin(LL n){
LL x
=n-1,t=0;
while ((x&1)==0) x>>=1,t++;
bool flag=1;
if (t>=1&& (x&1)==1){
for (int k=0;k<S;k++){
LL a
=rand()%(n-1)+1;
if (check(a,n,x,t)) {flag=1;break;}
flag
=0;
}
}
if (!flag || n==2) return0;
return1;
}

LL gcd(LL a,LL b){
if (a==0) return1;
if (a<0) return gcd(-a,b);
while (b){
LL t
=a%b; a=b; b=t;
}
return a;
}

LL Pollard_rho(LL x,LL c){
LL i
=1,x0=rand()%x,y=x0,k=2;
while (1){
i
++;
x0
=(muti_mod(x0,x0,x)+c)%x;
LL d
=gcd(y-x0,x);
if (d!=1&& d!=x){
return d;
}
if (y==x0) return x;
if (i==k){
y
=x0;
k
+=k;
}
}
}

void findfac(LL n){ //递归进行质因数分解N
if (!Miller_Rabin(n)){
factor[tot
++] = n;
return;
}
LL p
=n;
while (p>=n) p=Pollard_rho(p,rand() % (n-1) +1);
findfac(p);
findfac(n
/p);
}

int main(){
srand(time(NULL));
int t;
scanf(
"%d",&t);
while (t--){
LL n;
scanf(
"%I64d",&n);
if (!Miller_Rabin(n)) printf("Prime\n");
else{
tot
=0;
findfac(n);
LL ans
=n;
for (int i =0; i < tot; i++)
ans
= min(ans, factor[i]);
printf(
"%lld\n",ans);
}
}
}

你可能感兴趣的:(poj)