费马小定理:
a为整数,n是素数,且a,n互质,则有a^(n-1)≡1(mod n) ,即:a^(n-1)模n得1。
快速判定一个数是否为素数的方法:
如果存在一个整数a,使得a^(n-1)≡1(mod n)
,则称n为基于a的伪素数,当有多个满足关系的a时,则n为素数的概率趋向于1。所以取多个a测试一下即可。
二次探测定理:
如果n是一个素数,且n>x>0,则方程x²%n=1的解为:x=1或 x=n-1.
证明:
除x=1这个解外,剩下的x满足 n>x>√n , n²>x²>n;
那么则有x²=n+1 2n+1 3n+1……(n-2)n+1 …(n-1)n+1
由于n是素数,所以n不可分解,所以只有(n-2)n+1可化为平方形式,即x=n-1;
pollard rho算法
带有一定的概率性,错判率大概只有4^(-s),s值是自定的; 该算法主要是将大数不断分解为小数;
由费马小定理及伪质数推断可知,如果n是一个正整数,如果存在和n互素的正整数a满足 a^(n-1)≡ 1(mod
n),我们说n是基于a的伪素数。如果一个数是伪素数,那么它几乎肯定是素数,多次查询,则误判几率能降到极低;
所以不断构造随机数x1,找到这样一个因子p,使p=gcd(x1-x2,n);若p==1则构造失败,基于x1不断调整x2,否则p就是a的一个因数,递归继续找p,及n/p;
大素数判断:
Code:
LL mult( LL a , LL b , LL c ) { //快速乘法
a %= c ;
b %= c ;
LL ret = 0;
while( b ){
if( b & 1 ){
ret = ( ret + a ) % c ;
}
b >>= 1 ;
a <<= 1 ;
if( a >= c ) a %= c ;
}
return ret;
}
LL quick( LL a , LL b , LL m ){ // 快速幂
LL res = 1;
while( b ){
if( b & 1 ){
res = mult( res , a , m );
}
b >>= 1 ;
a = mult( a , a , m ) % m ;
}
return res ;
}
bool check( LL a, LL n , LL x , LL t ){
LL ret = quick( a , x , n );
LL last = ret ;
for( int i = 1 ; i <= t ; i++ ){
ret = mult( ret , ret , n ) ;
if( ret == 1 && last != 1 && last != n - 1 ) return true;
last = ret ;
}
if( ret != 1 ) return true ;
return false;
}
bool Miller_Rabin( LL n ){
if( n < 2 ) return false;
if( n == 2 ) return true;
if( !( n & 1 ) ) return false;
LL x = n - 1;
LL t = 0 ;
while( !(x & 1) ){
x >>= 1;
t ++ ;
}
srand(time(NULL));
for( int i = 0 ; i < S ; i++ ){ // S为自己设定的值,一般8-10次即可
LL a = rand() % ( n - 1 ) + 1;
if( check( a , n , x , t ) ) return false;
}
return true;
}
大整数的因数分解: (可以分解小于2 ^ 63的大整数)
Code:
const int S = 10;
LL mult( LL a , LL b , LL c ) {
a %= c ;
b %= c ;
LL ret = 0;
while( b ){
if( b & 1 ){
ret = ( ret + a ) % c ;
}
b >>= 1 ;
a <<= 1 ;
if( a >= c ) a %= c ;
}
return ret;
}
LL quick( LL a , LL b , LL m ){
LL res = 1;
while( b ){
if( b & 1 ){
res = mult( res , a , m );
}
b >>= 1 ;
a = mult( a , a , m ) % m ;
}
return res ;
}
bool check( LL a, LL n , LL x , LL t ){
LL ret = quick( a , x , n );
LL last = ret ;
for( int i = 1 ; i <= t ; i++ ){
ret = mult( ret , ret , n ) ;
if( ret == 1 && last != 1 && last != n - 1 ) return true;
last = ret ;
}
if( ret != 1 ) return true ;
return false;
}
bool Miller_Rabin( LL n ){
if( n < 2 ) return false;
if( n == 2 ) return true;
if( !( n & 1 ) ) return false;
LL x = n - 1;
LL t = 0 ;
while( !(x & 1) ){
x >>= 1;
t ++ ;
}
srand(time(NULL));
for( int i = 0 ; i < S ; i++ ){
LL a = rand() % ( n - 1 ) + 1;
if( check( a , n , x , t ) ) return false;
}
return true;
}
LL factor[100];
int tot ;
LL gcd( LL a , LL b){ //这样gcd可以求负数
if( !a ) return 1;
if( a < 0 ) return gcd( -a , b );
while( b ){
LL t = a % b ;
a = b ;
b = t ;
}
return a;
}
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 = ( mult( 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;
}
}
}
void findfac( LL n , int k ){
if( n == 1 ) return;
if( Miller_Rabin(n) ){
factor[tot++] = n ;
return ;
}
LL p = n ;
int c = k ;
while( p >= n ) p = pollard_rho( p , c-- );
findfac( p , k );
findfac( n / p , k );
}
例题: POJ1811
题意:判断一个数是否是素数,不是就输出它的最小的素因数
注意:这题交G++ RE的话交C++。
Code:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const int S = 10;
LL mult( LL a , LL b , LL c ) {
a %= c ;
b %= c ;
LL ret = 0;
while( b ){
if( b & 1 ){
ret = ( ret + a ) % c ;
}
b >>= 1 ;
a <<= 1 ;
if( a >= c ) a %= c ;
}
return ret;
}
LL quick( LL a , LL b , LL m ){
LL res = 1;
while( b ){
if( b & 1 ){
res = mult( res , a , m );
}
b >>= 1 ;
a = mult( a , a , m ) % m ;
}
return res ;
}
bool check( LL a, LL n , LL x , LL t ){
LL ret = quick( a , x , n );
LL last = ret ;
for( int i = 1 ; i <= t ; i++ ){
ret = mult( ret , ret , n ) ;
if( ret == 1 && last != 1 && last != n - 1 ) return true;
last = ret ;
}
if( ret != 1 ) return true ;
return false;
}
bool Miller_Rabin( LL n ){
if( n < 2 ) return false;
if( n == 2 ) return true;
if( !( n & 1 ) ) return false;
LL x = n - 1;
LL t = 0 ;
while( !(x & 1) ){
x >>= 1;
t ++ ;
}
srand(time(NULL));
for( int i = 0 ; i < S ; i++ ){
LL a = rand() % ( n - 1 ) + 1;
if( check( a , n , x , t ) ) return false;
}
return true;
}
LL factor[100]; // 存储因数,无序
int tot ;
LL gcd( LL a , LL b){ //这样gcd可以求负数
if( !a ) return 1;
if( a < 0 ) return gcd( -a , b );
while( b ){
LL t = a % b ;
a = b ;
b = t ;
}
return a;
}
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 = ( mult( 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;
}
}
}
void findfac( LL n , int k ){
if( n == 1 ) return;
if( Miller_Rabin(n) ){
factor[tot++] = n ;
return ;
}
LL p = n ;
int c = k ;
while( p >= n ) p = pollard_rho( p , c-- );
findfac( p , k );
findfac( n / p , k );
}
int main(){
int T;
scanf("%d",&T);
LL n ;
while( T-- ){
scanf("%lld",&n);
if( Miller_Rabin(n) ){
printf("Prime\n");
}else{
tot = 0 ;
findfac( n , 107 ) ;
LL ans = factor[0];
for( int i = 1 ; i < tot ; i++ ){
ans = min( ans , factor[i] );
}
printf("%lld\n",ans);
}
}
return 0 ;
}