题目链接: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; }