【poj 3641】 Pseudoprime numbers 【Waterloo Local Contest, 2007.9.23】

本文介绍如何使用费马小定理来判断一个数是否为特定基数的伪素数,并提供了通过Miller测试实现这一过程的C++代码示例。

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

Description

Fermat's theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p, the remainder is a. Some (but not very many) non-prime values of p, known as base-pseudoprimes, have this property for some a. (And some, known as Carmichael Numbers, are base-a pseudoprimes for all a.)

Given 2 < p ≤ 1000000000 and 1 < a < p, determine whether or not p is a base-a pseudoprime.

Input

Input contains several test cases followed by a line containing "0 0". Each test case consists of a line containing p and a.

Output

For each test case, output "yes" if p is a base-a pseudoprime; otherwise output "no".

Sample Input

3 2
10 3
341 2
341 3
1105 2
1105 3
0 0

Sample Output

no
no
yes
no
yes
yes

这道题是判断p是否为一个a-伪素数的题目,可以用Miller测试解决,下面是代码:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<iostream>
#define ll long long
using namespace std;
ll random(ll n){
	return ((ll)(rand())*rand()*rand())%n+1;
}
ll read(){
	ll s=0;
	char c=getchar();
	while(c<'0'||c>'9'){
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		s*=10;
		s+=c-'0';
		c=getchar();
	}
	return s;
}
ll q(ll a,ll b,ll k){
	a%=k;
	ll r=a,s=1;
	while(b){
		if(b&1){
			s*=r;
			s%=k;
		}
		r*=r;
		r%=k;
		b>>=1;
	}
	return s;
}
bool p(ll a,ll n){
	ll m=n-1;
	int k=0;
	while(!(m&1)){
		k++;
		m>>=1;
	}
	ll x=q(a,m,n);
	if(x==1||x==n-1){
		return 0;
	}
	while(k--){
		x=(x*x)%n;
		if(x==n-1){
			return 0;
		}
	}
	return 1;
}
bool check(ll n){
	int i;
	if(n==1||(!(n&1))){
		return 0;
	}
	if(n==2){
		return 1;
	}
	for(i=0;i<10;i++){
		ll x=random(n-2)+1;
		if(p(x,n)){
			return 0;
		}
	}
	return 1;
}
int main(){
	srand((unsigned)(time(NULL)));
	ll p,a;
	p=read();
	a=read();
	while(p||a){
		if(check(p)){
			printf("no\n");
		}
		else{
			if(q(a,p,p)==a){
				printf("yes\n");
			}
			else{
				printf("no\n");
			}
		}
		p=read();
		a=read();
	}
	return 0;
}

注:随机次数越多,错误几率越小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值