您的位置:首页 > 其它

POJ1811 PrimeTest Miller-Robin+Pollard-Rho

2016-09-15 16:05 369 查看
题意:T个数,若为素数则输出Prime,否则输出其最小的质因子。

思路:

(1)素数判定(Miller-Robin):

根据费马小定理,有:

a ^ (p - 1) % p = 1;

其中p为素数,0 < a < p。

于是我们随机生成a,验证p是否满足条件即可,为了尽量减少错误概率,可以生成多个不同的a。

(2)质因数分解(Pollard-Rho):

依旧是随机算法,设 1 < x, y < n, (x, y为随机生成)

每次判断t = gcd(|x - y|, n)是否为1, 若不是则t为n的一个因数,递归分解 t 与 n / t,并判断是否已分解为素数(研究表明,|x - y|比 x 更不容易与n互质,虽然不会证->__->);

若互质,则令x = (x * x + c) % n, 可以证明x必定会出现循环,所以用y来判断是否重复,如果出现了循环却还未找到因数,再随机出个c继续判断即可。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#define For(i,j,k) for(int i = j;i <= k;i ++)

using namespace std;
typedef long long LL;
LL Ans;

LL Mult(LL a, LL b, LL Mod){
LL s = 0;
while(b){
if(b & 1LL) s = (s + a) % Mod;
a = (a << 1) % Mod;
b >>= 1;
}
return s;
}

LL Pow(LL a, LL b, LL Mod){
LL s = 1;
while(b){
if(b & 1LL)s = Mult(s, a, Mod);
a = Mult(a, a, Mod);
b >>= 1;
}
return s;
}

LL c[60];
bool Miller_Robin(LL x){
if(x == 2)return true;
int T = 20;
LL k = 0, u = x - 1;
while(!(u & 1LL)) u >>= 1, ++k;
while(T--){
LL R = rand() % (x - 2) + 2, i = k;
c[i] = Pow(R, u, x);
while(i--){
c[i] = Mult(c[i+1], c[i+1], x);
if(c[i] == 1 && c[i+1] != 1 && c[i+1] != x - 1)
return false;
}
if(c[0] != 1)return false;
}
return true;
}

LL gcd(LL x, LL y){
return y ? gcd(y, x % y) : x;
}

LL Pollard_Rho(LL x, LL c){
LL u = rand() % (x - 1) + 1, v = u, L = 1, R = 2;
while(1){
++L;
u = (Mult(u, u, x) + c) % x;
if(u == v)return x;
LL fac = gcd((u - v + x) % x, x);
if(fac != 1 && fac != x) return fac;
if(L == R){
R <<= 1;
v = u;
}
}
}

void Findfac(LL x){
if(Miller_Robin(x)){
Ans = min(x, Ans);
return;
}
LL p = Pollard_Rho(x, rand());
while(p == x)p = Pollard_Rho(x, rand());
Findfac(p);
Findfac(x / p);
}

int main(){
int T;
LL n;
scanf("%d", &T);
while(T--){
scanf("%lld", &n);
if(Miller_Robin(n)) puts("Prime");
else{
Ans = 1LL << 60;
Findfac(n);
printf("%lld\n", Ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj