poj 1811 (prime test)

该博客主要介绍如何解决POJ 1811问题,即通过输入的整数n判断其是否为质数。文章提到采用Miller-Rabin算法,基于费马小定理进行质数检测,并提及了通过计算约数寻找数的最小质因子的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POJ - 1811


Time Limit:6000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u

Status

Description

Given a big integer number, you are required to find out whether it's a prime number.

Input

The first line contains the number of test cases T (1 <= T <= 20 ), then the following T lines each contains an integer number N (2 <= N < 2 54).

Output

For each test case, if N is a prime number, output a line containing the word "Prime", otherwise, output a line containing the smallest prime factor of N.

Sample Input

2
5
10

Sample Output

Prime
2


题意:输入T个n, 如果n是质数,输出Prime,否则输出n的最小质因子


本题使用Miller_Rabin判质数方法,它的依据为费马小定理,取若干个a进行验证,如果中间结果以及结果皆为1,则认为x为质数

还有算约数的方法,本质是: 随机一个值,让它在某个规则下出现环\


(下方来自段大神)

题意:T个数,若为素数则输出Prime,否则输出其最小的质因子。
思路:
(1)素数判定(Miller-Robin):
根据费马小定理,有:
a ^ (p - 1) % p = 1;
其中p为素数,0 < a < p。
于是我们随机生成a,验证p是否满足条件即可,为了尽量减少错误概率,可以生成多个不同的a。
(2)质因数分解(Pollard-Rho):
依旧是随机算法,设 1 < x, y < n, (x, y为随机生成)
每次判断t = gcd(|x - y|, n)是否为1, 若不是则t为n的一个因数,递归分解 t 与 n / t,并判断是否已分解为素数(研究表明,|x - y|比 x 更不容易与n互质,虽然不会证->__->);
若互质,则令x = (x * x + c) % n, 可以证明x必定会出现循环,所以用y来判断是否重复,如果出现了循环却还未找到因数,再随机出个c继续判断即可。



#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;

#define LL long long
#define MAXN (100+5)

LL ans;
LL X[MAXN];

LL multi(LL x, LL y, LL n){
	LL ret = 0;

	while(y){
		if(y & 1LL) ret = (ret+x) % n;
		x = (x+x) % n;
		y >>= 1;
	}

	return ret;
}

LL Base(LL x, LL y, LL n){
	LL ret = 1LL;
	
	while(y){
		if(y & 1LL) ret = multi(ret, x, n);
		x = multi(x, x, n);
		y >>= 1;
	}

	return ret;
}

bool Miller_Rabin(LL n){
	if(n == 2) return true;
	
	LL s = 20, t = 0, u = n-1;
	while(!(u&1)){
		t++; u >>= 1;
	}

	while(s--){
		LL a = rand()%(n-1) + 1;

		X[0] = Base(a, u, n);
		for(LL i = 1; i <= t; i++){
			X[i] = multi(X[i-1], X[i-1], n);
			if(X[i] == 1 && X[i-1] != 1 && X[i-1] != (n-1)) return false;
		}
		if(X[t] != 1) return false;
	}

	return true;
}

LL gcd(LL a, LL b){
	return !b? a: gcd(b, a%b);
}

LL Pollard_Rho(LL n, LL c){
	LL i = 1LL, k = 2LL, x = rand()%(n-1)+1, y = x;

	while(true){
		i++;
		x = (multi(x, x, n) + c) % n;
		LL p = gcd((y-x+n)%n, n);
		
		if(p != 1 && p != n) return p;
		if(x == y) return n;

		if(i == k){
			y = x;
			k <<= 1;
		}
	}
}

void find(LL n, LL c){
//	printf("n = %lld\n", n);
	if(n == 1) return;
	if(Miller_Rabin(n)){
		ans = min(ans, n);
		return;
	}
//	printf("yes!\n");

	LL p = n, k = c;
	while(p == n) p = Pollard_Rho(p, c--);
	
	find(p, k); find(n/p, k);
}

int main(){
//	freopen("test.in", "r", stdin);
	
	int T;
	scanf("%d", &T);

	while(T--){
		LL n;
		scanf("%lld", &n);
		
		ans = (1LL<<62);
		find(n, 120);
		
		if(ans == n) printf("Prime\n");
		else printf("%lld\n", ans);
	}

	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值