素数判定的模板题,运用米勒-罗宾素数判定,然后用Pollard_Rho法求出质因数。使用相应的模板即可,不过注意存储质因子的数组需要使用vector,并且使用long long类型存储,不然存储不下,而且输出最下的质因子时,需要写个迭代器进行查询。

完整代码如下:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

typedef long long  LL;
vector <LL> fac;
LL gcd(LL a, LL b)
{
    return b == 0 ? a : gcd(b, a%b);
}

LL mul_mod(LL a, LL x, LL n)   ///计算a*x%n,其中t用于存储结果,当t>=n的时候,t对n的模减去n即可(不会出现t>=2*n的情况,因为a也对n取了模)
{
    LL t = 0;
    while(x)
    {
        if(x & 1)
        {
            t += a;
            if(t >= n) t -= n;
        }
        a <<= 1;
        if(a >= n) a -= n;
        x >>= 1;
    }
    return t;
}

LL pow2_mod(LL a, LL x, LL n)///           //乘方快速幂
{
    LL t = 1;
    a %= n;
    while(x)
    {
        if(x & 1) t = mul_mod(t, a, n);
        a = mul_mod(a, a, n);
        x >>= 1;
    }
    return t;
}
///不断选取不超过n-1的基b(s次),计算是否每次都有b^(n-1) ≡ 1(mod n),若每次都成立则n是素数,否则为合数。 
bool test(LL n, LL a, LL d)///n 为测试数,a为素数表中的数,d为正奇数,这里运用位运算,将n-1不断通过快速幂,同时将n-1向左位移,进行抽出指数中2的操作,从而不断进行素数检测
{
    if(n == 2) return true;///为2肯定是素数
    if(n == a) return true;///如果n等于素数表里面的数则肯定是素数
    if((n&1) == 0) return false;///如果是偶数,则肯定不是素数
    while(!(d&1)) d >>=1;///选取奇数
    LL t = pow2_mod(a, d, n);///进行快速幂运算
    while((d != n-1) && (t != 1) && (t != n-1))///由二次探测定理可知,只有当t等于1或者n-1时,n才为素数
    {
///        t = (LL)t*t%n;
        t = mul_mod(t, t, n);
        d = d<<1;
    }
    return (t == n-1 || (d&1) == 1);
}

bool isPrime(LL n)
{
    ///有些题目把1看作质数,但是负数不会是质数
    if(n < 2) return false;
    LL a[] = {2, 3, 61};
    for(int i = 0; i <= 2; i++) if(!test(n, a[i], n-1)) return false;
    return true;
}

LL Pollard_Rho(LL n, LL c)
{
    LL x, y, d;
    LL i = 1, k = 2;
    x = y = rand() % n;
    do
    {
        i++;
        d = gcd(n + y - x, n);
        if(d > 1 && d < n) return d;
        if(i == k)
        {
            y = x;
            k <<= 1;
        }
        x = (mul_mod(x, x, n) + n - c) % n;
    }
    while(y != x);
    return n;
}
void rhoAll(LL n)
{
    if(n <= 1) return;
    if(isPrime(n))
    {
        fac.push_back(n);
        return;
    }
    LL t = n;
    while(t >= n)
        t = Pollard_Rho(n, rand() % (n-1) + 1);
    rhoAll(t);
    rhoAll(n/t);
    return;
}

int main()
{
    LL n;
    int t;
    cin>>t;
    while(t--)
    {
        while(cin>>n)
        {
            if(isPrime(n))
                cout<<"Prime"<<endl;
            else
            {
                fac.clear();
                rhoAll(n);
                LL mins=100000000000;
                for(vector<LL> ::iterator it=fac.begin();it!=fac.end();++it)
                    mins=min(mins,*it);
                    cout<<mins<<endl;
            }
        }
    }
    return 0;
}

 

其中米勒-罗宾判断法模板如下:

typedef long long  LL;
LL gcd(LL a, LL b)
{
    return b == 0 ? a : gcd(b, a%b);
}

LL mul_mod(LL a, LL x, LL n)   ///计算a*x%n,其中t用于存储结果,当t>=n的时候,t对n的模减去n即可(不会出现t>=2*n的情况,因为a也对n取了模)
{
    LL t = 0;
    while(x)
    {
        if(x & 1)
        {
            t += a;
            if(t >= n) t -= n;
        }
        a <<= 1;
        if(a >= n) a -= n;
        x >>= 1;
    }
    return t;
}

LL pow2_mod(LL a, LL x, LL n)///           //乘方快速幂
{
    LL t = 1;
    a %= n;
    while(x)
    {
        if(x & 1) t = mul_mod(t, a, n);
        a = mul_mod(a, a, n);
        x >>= 1;
    }
    return t;
}
///不断选取不超过n-1的基b(s次),计算是否每次都有b^(n-1) ≡ 1(mod n),若每次都成立则n是素数,否则为合数。 
bool test(LL n, LL a, LL d)///n 为测试数,a为素数表中的数,d为正奇数,这里运用位运算,将n-1不断通过快速幂,同时将n-1向左位移,进行抽出指数中2的操作,从而不断进行素数检测
{
    if(n == 2) return true;///为2肯定是素数
    if(n == a) return true;///如果n等于素数表里面的数则肯定是素数
    if((n&1) == 0) return false;///如果是偶数,则肯定不是素数
    while(!(d&1)) d >>=1;///选取奇数
    LL t = pow2_mod(a, d, n);///进行快速幂运算
    while((d != n-1) && (t != 1) && (t != n-1))///由二次探测定理可知,只有当t等于1或者n-1时,n才为素数
    {
///        t = (LL)t*t%n;
        t = mul_mod(t, t, n);
        d = d<<1;
    }
    return (t == n-1 || (d&1) == 1);
}

bool isPrime(LL n)
{
    ///有些题目把1看作质数,但是负数不会是质数
    if(n < 2) return false;
    LL a[] = {2, 3, 61};
    for(int i = 0; i <= 2; i++) if(!test(n, a[i], n-1)) return false;
    return true;
}

Pollard_Rho法求大数的质因子代码模板如下:

vector <LL> fac;
LL Pollard_Rho(LL n, LL c)
{
    LL x, y, d;
    LL i = 1, k = 2;
    x = y = rand() % n;
    do
    {
        i++;
        d = gcd(n + y - x, n);
        if(d > 1 && d < n) return d;
        if(i == k)
        {
            y = x;
            k <<= 1;
        }
        x = (mul_mod(x, x, n) + n - c) % n;
    }
    while(y != x);
    return n;
}
void rhoAll(LL n)
{
    if(n <= 1) return;
    if(isPrime(n))
    {
        fac.push_back(n);
        return;
    }
    LL t = n;
    while(t >= n)
        t = Pollard_Rho(n, rand() % (n-1) + 1);
    rhoAll(t);
    rhoAll(n/t);
    return;
}

迭代器书写格式如下:

vector<LL> ::iterator it=fac.begin()///用于遍历vector数组