POJ 1811 Prime Test

链接: http://poj.org/problem?id=1811

判断一个数是否为素数,如果不是的话,输出最小的素因子  范围 n <=2^54

从大小上来看,普通方法一定搞不定!故只能参考大牛blog 及代码 搞的

采用Miller-Rabin随机素数测试法 + Pollard_rho启发式分解因子法(算法导论有介绍,具体东东木看很懂也)

其中随机素数测试法基于两个定理和一个推论:

1.如果n是素数那么对于a<n,有a^(n - 1) mod n = 1. 该定理被称为费马小定理。

2.如果n是奇素数,那么x^2 mod n =1.仅有两个根,x = 1,和x = -1.

3.如果模n存在1的非平凡平方根,那么n是合数。

根据上述条件就可以判断一个数是否为素数了!

 Pollard_rho 启发式分解因子法表示木看懂,看导论去吧自己!为什么每次 c--  呢,求解释!

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef __int64 int64 ;
#define INF 99999999999999
#define Rand_time 5					//随机次数与正确率有关
#define C 16381
int64 MIN;
int64 Gcd(int64 a,int64 b)			//最大公约数,不解释
{
	return a%b?Gcd(b,a%b):b;
}
int64 Multi_mod(int64 a,int64 b,int64 n)	//(a*b)%n 直接计算有超出int64表示范围,故采取加法变形来计算值
{											
	int64 s = 0;
	while(b){
		if(b&1)s = (s+a)%n;
		a = (a+a)%n;
		b >>= 1;
	}
	return s;
}
int64 Pow_mod(int64 a,int64 b,int64 n)		//标准的快速求幂,不解释
{
	int64 s=1;
	while(b){
		if(b&1) s = Multi_mod(s,a,n);
		a = Multi_mod(a,a,n);
		b >>= 1;
	}
	return s;
}

int Prime_test(int64 n)
{
	int64 u = n-1,pre,x;
	int i,j,k=0;
	if( n == 2 || n == 3 || n==5 || n==7 || n==11)return 1;
	if( n == 1 || (!(n%2)) ||(!(n%3)) || (!(n%5)) || (!(n%7)) || (!(n%11)))return 0;
	for(;!(u&1);k++,u>>=1);
	srand((int64)time(0));		//随机参数
	for(i=0;i<Rand_time;i++){
		x = rand()%(n-2) + 2;	//保证数据大于等于2
		if(x%n==0)continue;
		x = Pow_mod(x,u,n);		//计算x^u
		pre = x;				//保留x,既x^2 mod n =1 的根
		for(j=0;j<k;j++){		//如果n是素数那么x^2mod n = 1,仅有两个根(不同余),+1和-1(n-1)
			x = Multi_mod(x,x,n);
			if(x==1 && pre != 1 &&pre != (n-1))
				return 0;
			pre = x;
		}
		if( x != 1)return 0;	//费马小定理 a^(n-1) mod n 恒等于 1 则可以认为 n 是素数
	}
	return 1;
}
int64 rho(int64 n ,int c)
{
	int64 x,y,d;
	int i = 1,j =2;
	srand((int64)time(0));
	x = rand()%(n-1)+1;
	y = x;
	while(1){
		i ++;
		x = (Multi_mod(x,x,n)+c)%n;
		d = Gcd(y-x+n,n);
		if(d!=1 && d!=n)return d;
		if(x==y)return n;
		if(i==j){
			y = x;
			j<<=1;
		}
	}
}
void find_factor(int64 n ,int c)
{
	int64 r,d;
	if( n <=1)return ;
	if(Prime_test(n)){
		if(MIN > n) MIN = n;
		return ;
	}
	r = rho(n,c--);			//不明白为什么 c-- ,求包养
	d = n/r;
	find_factor(d,c);
	find_factor(r,c);
}
int main()
{
	int T;
	int64 n;
	scanf("%d",&T);
	while(T--){
		scanf("%I64d",&n);
		if(Prime_test(n))puts("Prime");
		else {
			MIN  = INF;
			find_factor(n,C);
			printf("%I64d\n",MIN);
		}
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值