题目链接:http://poj.org/problem?id=1811
题目意思:给出一个数判断是否是素数,若不是素数,求出最小质因子
费马小定理:若p是素数,则有 a^(p-1) =1 (mod p ) , 1<=a<=n-1。
二次探测定理: 若p是素数,对于 0<x<p ,有 x^2= 1 ( mod p) 的解 x=1, p-1。
首先是素数的测试,根据费马小定理和二次探测定理对素数进行测试
整数分解: n为待分解数,
1 找出两个数x,y ,求d=gcd( y - x, n)
2 若1<d< n 返回d; 若y==x 返回n;
当分解出一个约数之后,用分治的方法求出最小质因子
代码如下:
//============================================================================
// Name : poj1811.cpp
// Author : ssslpk
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstdlib>
#define int64 long long
#define TIME 12
#define inf 1e10
using namespace std;
int64 minn;
int64 gcd(int64 a,int64 b){return b? gcd(b,a%b):a;}
int64 mod_mult(int64 a,int64 b,int64 n)// 求 (a * b)%n
{
int64 s=0;
a=a%n;
while(b)
{
if(b&1) s=(s+a)%n;
a<<=1;
a=a%n;
b>>=1;
}
return s;
}
int64 mod_exp(int64 a,int64 b,int64 n)// 求(a ^ b)%n
{
int64 d=1;a%=n;
while(b>=1)
{
if(b&1)d=mod_mult(d,a,n);
a=mod_mult(a,a,n);
b>>=1;
}
return d;
}
bool witness(int64 a, int64 n)
{
int64 m, x, y;
int64 i, j = 0;
m = n - 1;
while (m % 2 == 0)
{
m = m >> 1;
j++;
}
x = mod_exp(a, m, n);
for (i = 1; i <= j; i++) {
y = mod_exp(x, 2, n);
if ((y == 1) && (x != 1) && (x != n - 1))
return false;
x = y;
}
return y==1;
}
bool miler(int64 n)
{
if(n==2)return true;
if(n%2==0 || n==1)return false;
for(int i=0;i<TIME;i++)
{
int64 x=rand()%(n-1)+1;
// int64 x=rand()*(n-2)%RAND_MAX+1;
if(! witness(x,n))return false;
}
return true;
}
int64 Pollard(int64 n,int64 c)
{
int64 i,k,x,y,d;
srand(time(NULL));
i=1;k=2;
x=rand()%n;
y=x;
while(1)
{
i++;
x=(mod_mult(x,x,n)+c)%n;
d=gcd(y-x,n);
if(d>1 && d<n )return d;
if(y==x)return n;
if(i==k)
{
y=x;
k=k<<1;
}
}
}
void find_min(int64 n,int64 c)
{
if(n==1)return;
if(miler(n))
{
if(n<minn)minn=n;
return ;
}
int64 m=Pollard(n,c--);
find_min(m,c);
find_min(n/m,c);
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
int64 n;
scanf("%lld",&n);
if(miler(n))printf("Prime\n");
else
{
minn=inf;
find_min(n,240);
printf("%lld\n",minn);
}
}
return 0;
}