POJ1811 Prime Test(Miller-Rabin素数测试算法与Pollard Rho因子分解算法)

题意:给出一个N(2 <= N < 2^54),如果是素数,输出"Prime",否则输出最小的素因子

#include <iostream>   //该程序为哥德巴赫猜(想输出所有的组合)
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <algorithm>

using namespace std;

typedef unsigned long long ull;
typedef unsigned long long LL;

LL n,ans,factor[10001];//质因数分解结果(刚返回时是无序的)
LL tol;//质因数的个数,数组下标从0开始

LL prime[6] = {2, 3, 5, 233, 331};
LL qmul(LL x, LL y, LL mod) { // 乘法防止溢出, 如果p * p不爆LL的话可以直接乘; O(1)乘法或者转化成二进制加法
//快速乘法取模算法

    return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
    /*
    LL ret = 0;
    while(y) {
        if(y & 1)
            ret = (ret + x) % mod;
        x = x * 2 % mod;
        y >>= 1;
    }
    return ret;
    */
}

LL qpow(LL a, LL n, LL mod) {
    LL ret = 1;
    while(n) {
        if(n & 1) ret = qmul(ret, a, mod);
        a = qmul(a, a, mod);
        n >>= 1;//n=n/2二进制乘除法
    }
    return ret;
}


bool Miller_Rabin(LL p) {
    if(p < 2) return 0;
    if(p != 2 && p % 2 == 0) return 0;
    LL s = p - 1;
    while(! (s & 1)) s >>= 1;//排除掉偶数
    for(int i = 0; i < 5; ++i) {
        if(p == prime[i]) return 1;
        LL t = s, m = qpow(prime[i], s, p);
        //二次探测定理卡米歇尔数保证该数为素数
        //卡米歇尔数若一个数为合数当0<x<p,则方程x^p≡a(mod p)
        //二次探测定理如果p是一个素数,0<x<p,则方程x^2≡1(mod p)的解为x=1,p-1
        while(t != p - 1 && m != 1 && m != p - 1) {
            m = qmul(m, m, p);
            t <<= 1;
        }
        if(m != p - 1 && !(t & 1)) return 0;//不是奇数且m!=p-1
    }
    return 1;
}

LL gcd(LL a,LL b)
{
    if(a==0)return 1;
    if(a<0) return gcd(-a,b);
    while(b)
    {
        long long t=a%b;
        a=b;
        b=t;
    }
    return a;
}
LL Pollard_rho(LL x,LL c)
{
    LL i=1,k=2;
    LL x0=rand()%x;
    LL y=x0;
    while(1)
    {
        i++;
        x0=(qmul(x0,x0,x)+c)%x;
        long long d=gcd(y-x0,x);
        if(d!=1&&d!=x) return d;
        if(y==x0) return x;
        if(i==k)
        {
            y=x0;
            k+=k;
        }
    }
}
//对n进行素因子分解
void findfac(LL n)
{
    if(Miller_Rabin(n))//素数
    {
        factor[tol++]=n;
        return;
    }
    LL p=n;
    while(p>=n) p=Pollard_rho(p,rand()%(n-1)+1);
    findfac(p);//递归调用
    findfac(n/p);
}


int main()
{
    int T;
    long long x;
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>T;
    while(T--)
    {
        cin>>x;
        if(Miller_Rabin(x)) cout<<"Prime"<<endl;
        else
        {
            tol=0;
            findfac(x);
            long long ans=factor[0];
            for(int i=1;i<tol;i++)
                if(ans>factor[i])
                    ans=factor[i];
            cout<<ans<<endl;
        }
    }

}

Pollard Rho因子分解算法:https://www.cnblogs.com/dalt/p/8437119.html

posted @ 2018-08-07 16:15  Somnus、M  阅读(117)  评论(0编辑  收藏  举报