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