POJ1811 PrimeTest Miller-Robin+Pollard-Rho

题意: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;
}



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值