poj1811(pollard_rho模板)

Posted ygeloutingyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj1811(pollard_rho模板)相关的知识,希望对你有一定的参考价值。

题目链接: http://poj.org/problem?id=1811

 

题意: 判断一个数 n (2 <= n < 2^54)是否为质数, 是的话输出 "Prime", 否则输出其第一个质因子.

 

思路: 大数质因子分解, 直接用 pollard_rho (详情参见: http://blog.csdn.net/maxichu/article/details/45459533) 模板即可.

 

代码:

技术分享
  1 #include <iostream>
  2 #include <algorithm>
  3 #define ll long long
  4 using namespace std;
  5 
  6 const int MAXN = 1e2;
  7 const int repeat = 8;//repeat为检测次数,判断错误率为4^-repeat,一般8~10就够了
  8 
  9 ll get_mult(ll a, ll b, ll c){//返回a*b%c
 10     a %= c;
 11     b %= c;
 12     ll ret = 0;
 13     while(b){
 14         if(b & 1){
 15             ret += a;
 16             if(ret >= c) ret -= c;
 17         }
 18         b >>= 1;
 19         a <<= 1;
 20         if(a >= c) a -= c;
 21     }
 22     return ret;
 23 }
 24 
 25 ll get_pow(ll x, ll n, ll mod){//返回x^n%mod
 26     ll ret = 1;
 27     x %= mod;
 28     while(n){
 29         if(n & 1) ret = get_mult(ret, x, mod);
 30         x = get_mult(x, x, mod);
 31         n >>= 1;
 32     }
 33     return ret;
 34 }
 35 
 36 //通过 a^(n-1) = 1(mod n) 来判断n是否为素数
 37 //n-1 = x*2^t 中间使用二次探测定理
 38 //是合数返回true,不一定是合数返回false
 39 bool cherk(ll a, ll n, ll x, ll t){
 40     ll ret = get_pow(a, x, n);
 41     ll last = ret;
 42     for(int i = 1; i <= t; i++){
 43         ret = get_mult(ret, ret, n);
 44         if(ret == 1 && last != 1 && last != n - 1) return true;
 45         last = ret;
 46     }
 47     if(ret != 1) return true;
 48     return false;
 49 }
 50 
 51 bool Miller_Rabin(ll n){
 52     if(n < 2) return false;
 53     if(n == 2) return true;
 54     if(!(n & 1)) return false;//偶数
 55     ll x = n - 1, t = 0;
 56     while(!(x & 1)){
 57         x >>= 1;
 58         t++;
 59     }
 60     // srand(time(NULL));
 61     for(int i = 0; i < repeat; i++){
 62         ll a = rand() % (n - 1) + 1;
 63         if(cherk(a, n, x, t)) return false;
 64     }
 65     return true;
 66 }
 67 
 68 ll factor[MAXN];
 69 int tot;//n的质因子个数
 70 
 71 ll get_gcd(ll a, ll b){
 72     ll tmp;
 73     while(b){
 74         tmp = a;
 75         a = b;
 76         b = tmp % b;
 77     }
 78     return a >= 0 ? a : -a;
 79 }
 80 
 81 ll pollard_rho(ll x, ll c){//返回x的一个因子
 82     ll i = 1, k = 2;
 83     // srand(time(NULL));
 84     ll x0 = rand() % (x - 1) + 1;
 85     ll y = x0;
 86     while(1){
 87         i++;
 88         x0 = (get_mult(x0, x0, x) + c) % x;
 89         ll d = get_gcd(y - x0, x);
 90         if(d != 1 && d != x) return d;
 91         if(y == x0) return x;
 92         if(i == k){
 93             y = x0;
 94             k += k;
 95         }
 96     }
 97 }
 98 
 99 void findfac(ll n, int k){//对n质因分解并将结果保存到factor中
100     if(n == 1) return;
101     if(Miller_Rabin(n)){
102         factor[tot++] = n;
103         return;
104     }
105     ll p = n;
106     int c = k;//c防止死循环
107     while(p >= n){
108         p = pollard_rho(p, c--);
109     }
110     findfac(p, k);
111     findfac(n / p, k);
112 }
113 
114 int main(void){
115     ll n;
116     int t;
117     cin >> t;
118     while(t--){
119         cin >> n;
120         if(Miller_Rabin(n)) cout << "Prime" << endl;
121         else{
122             tot = 0;
123             findfac(n, 107);
124             ll sol = factor[0];
125             for(int i = 1; i < tot; i++){
126                 sol = min(sol, factor[i]);
127             }
128             cout << sol << endl;
129         }
130     }
131     return 0;
132 }
View Code

 

以上是关于poj1811(pollard_rho模板)的主要内容,如果未能解决你的问题,请参考以下文章

数学#素数判定Miller_Rabin+大数因数分解Pollard_rho算法 POJ 1811&2429

POJ 1811 大素数判断

随机素数测试(Miller_Rabin算法)和求整数素因子(Pollard_rho算法)

poj 2429GCD & LCM Inverse (Miller-Rabin素数测试和Pollard_Rho_因数分解)

POJ 2429 GCD & LCM Inverse(Pollard_Rho+dfs)

poj 1811: Prime Test