POJ 1811 Miller_Rabin+Pollard_Rho

本文介绍了一种用于测试大数是否为素数的方法,并给出了一种寻找大数最小因子的算法。主要通过Miller-Rabin素性测试来确定大数是否可能是素数,若非素数,则采用Pollard Rho算法找到最小因子。
摘要由CSDN通过智能技术生成

赤裸裸的模板题吧

一个大数,判断是否是素数,如果是合数输出最小的因子。

大数的素数测试,随机算法Miller_Rabin测试,前提是了解费马小定理。不过对于非平方根处有疑惑,还得请教大牛

至于输出最小因子,运用Pollard_Rho即可,也算是随机算法,怎么看都是要靠RP的,至于xi=xi-1^2+c ,这个c的取法一直不理解,我用的是240,有的人是使用随机数,网上有大牛说12323速度最快?

/*
ID:cxlove
PROB:poj 1811
HINT:Miller_Rabin+Pollard_Rho
*/
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstring>
#include<cstdlib>
#define C	240
#define TIME 10
#define LL long long
using namespace std;
LL ans;
LL gcd(LL a, LL b){
	if(a==0) return 1;
	if(a<0) return gcd(-a,b);
	return b==0?a:gcd(b,a%b);
}
LL MultMod(LL a,LL b,LL n){
	a%=n;
	b%=n;
	LL ret=0;
	while(b){
		if(b&1){
			ret+=a;
			if(ret>=n) ret-=n;
		}
		a=a<<1;
		if(a>=n) a-=n;
		b=b>>1;
	}
	return ret;
}
LL PowMod(LL a,LL n,LL m){
	LL ret=1;
	a=a%m;
	while(n>=1){
		if(n&1)
			ret=MultMod(ret,a,m);
		a=MultMod(a,a,m);
		n=n>>1;
	}
	return ret;
}
bool Witness(LL a,LL n){
	LL t=0,u=n-1;
	while(!(u&1)){
		t++;
		u/=2;
	}
	LL x0=PowMod(a,u,n);
	for(int i=1;i<=t;i++){
		LL x1=MultMod(x0,x0,n);
		if(x1==1&&x0!=1&&x0!=(n-1))
			return true;
		x0=x1;
	}
	if(x0!=1)
		return true;
	return false;
}
bool Miller_Rabin(LL n,int t){
	if(n==2) return true;
	if((n&1)==0)  return false;
	srand(time(NULL));
	for(int i=0;i<t;i++){
		LL a=rand()%(n-1)+1;
		if(Witness(a,n))
			return false;
	}
	return true;
}
LL Pollard_Rho(LL n,LL c){
	LL i=1,x=rand()%n,y=x,k=2;
	while(1){
		i++;
		x=(MultMod(x,x,n)+c)%n;
		LL d=gcd(y-x,n);
		if(d!=1&&d!=n)
			return d;
		if(x==y)
			return n;
		if(i==k){
			y=x;
			k*=2;
		}
	}
}
void get_small(LL n,LL c){
	if(n==1) return;
	if(Miller_Rabin(n,TIME)){
		ans=min(n,ans);
		return ;
	}
	LL p=n;
	while(p>=n) p=Pollard_Rho(p,c--);
	get_small(p,c);
	get_small(n/p,c);
}
int main(){
	srand(time(NULL));
	LL n;
	int t;
	scanf("%d",&t);
	while(t--){		
		scanf("%I64d",&n);
		if(Miller_Rabin(n,TIME))
			printf("Prime\n");
		else{ans=n;
			get_small(n,C);
			printf("%I64d\n",ans);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值