POJ Pseudoprime numbers( Miller-Rabin素数测试 )


**链接:****传送门 **

题意:题目给出费马小定理:Fermat's theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). 我们知道Miller-Rabin素数测试的算法原理就是基于费马小定理的,因为我们在测试底数的时候只是随机一些 a ,所以可能有的合数就脸一白通过了测试,于是就产生了伪素数这一概念,现在给你一对 p and a,判断 p 是否是以 a 为基的伪素数

思路:****对于素数来说是不存在伪素数这一说的,只有合数才可能出现伪素数,所以当 p 为合数 且满足式子:ap = a (mod p).则 p 是以 a 为基的伪素数


/*************************************************************************
    > File Name: poj3641.cpp
    > Author:    WArobot 
    > Blog:      http://www.cnblogs.com/WArobot/ 
    > Created Time: 2017年05月22日 星期一 14时56分11秒
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

#define TIME 1000		// 米勒测试次数上限
#define ll long long

ll RDM(ll n){	// 生成随机底数随机底数范围在[ 1 , n ]
	return (ll)( (double)rand()/RAND_MAX * n + 0.5 );	
}
ll quick_pow(ll a,ll x,ll m){ // O(logx)
	ll ret = 1;
	while(x){
		if( x&1 )	ret = ( (ret%m) * (a%m) ) % m;
		a = ( (a%m) * (a%m) ) % m;
		x >>= 1;
	}
	return ret;
}
bool Mille_Rabin(ll n){			// 复杂度大约为O(TIME)	PS:除非脸黑成功避过TIME次测试 
	for(int i = 1 ; i <= TIME ; i++){
		ll a = RDM(n-2) + 1;	// 随机底数
		if( quick_pow(a,n-1,n) != 1 )
			return false;
	}
	return true;
}
bool Pseudo_Prime(ll p,ll a){
	return quick_pow(a,p,p) == a ? true : false;
}
int main(){
	ll p , a;
	while(~scanf("%lld%lld",&p,&a)){
		if( p == 0 && a == 0 )		break;
	
		if( Mille_Rabin(p) ){
			printf("no
");
		}
		else{
			if( Pseudo_Prime(p,a) )	printf("yes
");
			else					printf("no
");
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/WArobot/p/6889555.html