POJ 1811 Prime Test (pollard_rho)

题意:给一个1e18的大数,求最小质因子

分析:裸板子题,可以测试板子,需要注意的是POJ G++不可以用srand,C++不可以用__gcd,而且__gcd存在出现负数的情况,所以还是手写一个gcd函数。

另外那个快速乘mul_mod这样写比较长但是可以优化大概10%的速度

代码:

#include <cmath> //定义数学函数
#include <cstdio> //定义输入/输出函数
#include <cstdlib> //定义杂项函数及内存分配函数
#include <cstring> //字符串处理
#include <algorithm> //STL 通用算法
#include <cmath>
#include <list> //STL 线性列表容器
#include <map> //STL 映射容器
#include <iostream>
#include <queue> //STL 队列容器
#include <set> //STL 集合容器#
#include <stack> //STL 堆栈容器
#include <string> //字符串类
#include <vector> //STL 动态数组容器
#include <sstream>
#include <ctime>
#define ll long long
using namespace std;
ll gcd(ll a,ll b)
{
    ll t;
    while(b)
    {
        t = a;
        a = b;
        b = t%b;
    }
    if(a >= 0)return a;
    else return -a;
}
//ret=(a*b)%c  0<=a,b<2^63  0<c<2^62
ll mul_mod(ll a,ll b,ll c)
{
    ll ret = 0;
    for(a%=c;b;b>>=1)
    {
        if(b&1)
        {
            ret+=a;
            if(ret>c)
                ret-=c;
        }
        a<<=1;
        if(a>c)
            a-=c;
    }
    return ret;
}
//ret = (a^b)%c
ll pow_mod(ll a,ll b,ll c)
{
    ll ret = 1;
    for(a%=c;b;b>>=1,a=mul_mod(a,a,c))
        if(b&1)ret=mul_mod(ret,a,c);
    return ret;
}
// 通过 a^(n-1)=1(mod n)来判断 n 是不是素数
// n - 1 = x * 2
// t 中间使用二次判断
// 是合数返回 true, 不一定是合数返回 false
bool check(ll a,ll n,ll x,ll t)
{
    ll ret = pow_mod(a,x,n);
    ll last = ret;
    for(int i = 1; i <= t; i++)
    {
        ret = mul_mod(ret,ret,n);
        if(ret == 1 && last != 1 && last != n-1)
            return true;//合数
        last = ret;
    }
    if(ret != 1)return true;
    else return false;
}
//**************************************************
// Miller_Rabin 算法
// 是素数返回 true,(可能是伪素数)
// 不是素数返回 false
//**************************************************
bool Miller_Rabin(ll n)
{
    if( n < 2)return false;
    if( n == 2)return true;
    if( (n&1) == 0)return false;//偶数
    ll x = n - 1;
    ll t = 0;
    while( (x&1)==0 )
    {
        x >>= 1;
        t++;
    }

    srand(time(NULL));/* *************** */

    for(int i = 0; i < 8; i++)//8~10次
    {
        ll a = rand()%(n-1) + 1;
        if( check(a,n,x,t) )return false;
    }
    return true;
}

//**********************************************
// pollard_rho 算法进行质因素分解
//*********************************************
map<ll,int>fac;//质因素分解结果

//找出一个因子
ll pollard_rho(ll x,ll c)
{
    ll i = 1, k = 2;
    srand(time(NULL));
    ll x0 = rand()%(x-1) + 1;
    ll y = x0;
    while(1)
    {
        i ++;
        x0 = (mul_mod(x0,x0,x) + c)%x;
        ll 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素因子存入 fac. k 设置为 107 左右即可
void findfac(ll n,int k=107)
{
    if(n == 1)return;
    if(Miller_Rabin(n))
    {
        fac[n]++;
        return;
    }
    ll p = n;
    int c = k;
    while( p >= n)
        p = pollard_rho(p,c--);//值变化,防止死循环
    findfac(p,k);
    findfac(n/p,k);
}
//POJ 1811
//给出一个N>1,素数输出"Prime",否则输出最小的素因子
int main()
{
    int _;cin>>_;
    while(_--)
    {
        ll n;cin>>n;
        fac.clear();
        findfac(n);
        if(fac.begin()->first==n)cout<<"Prime"<<endl;
        else cout<<fac.begin()->first<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值