POJ3641 Pseudoprime numbers - 樸素素數判斷 + 快速冪運算

Pseudoprime numbers

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 14334   Accepted: 6215

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-a 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(2&lt;p109,1&lt;a&lt;p)p,a(2&lt;p≤10^9,1&lt;a&lt;p) ,判斷 pp 是否是 baseabase-a pseudoprimepseudoprime . ppbaseabase-a pseudoprimepseudoprime ,當且僅當 pp合數ap=a(moda^p=a(mod p)p) .

 
 

分析:

由於 pp 最大隻會取到 10910^9 ,故可以採用樸素的素數判定方法在 O(p)O(\sqrt{p}) 的時間複雜度內判斷 pp 是否爲合數,且我們可以提前利用素數篩得到 104.510^{4.5} 以內的素數,以減少素數判定時考慮的因子個數。隨後我們只需要計算 apa^p ,由於 pp 較大,需要採用快速冪運算,這樣可以在 O(log2p)O(\log_2{p}) 的時間複雜度內計算出 apa^p modmod pp .

 
 
下面貼代碼:

#include <cstdio>
#include <cmath>
using namespace std;

typedef long long ll;
const int MAX_N = 32000;

bool ispr[MAX_N];
int primes[MAX_N];
int pcnt;

void getprime(const int N);
bool is_prime(int x);
ll mod_pow(ll x, ll p, ll m);

int main()
{
	getprime(MAX_N);

	int a, p;
	while (~scanf("%d%d", &p, &a) && a && p)
	{
		if (is_prime(p) || mod_pow(a, p, p) != a)
		{
			printf("no\n");
		}
		else
		{
			printf("yes\n");
		}
	}
	return 0;
}

ll mod_pow(ll x, ll p, ll m)
{
	ll res = 1;
	while (p)
	{
		if (p & 1)
		{
			res = res * x % m;
		}
		x = x * x % m;
		p >>= 1;
	}
	return res;
}

void getprime(const int N)
{
	for (int i = 2; i < N; ++i)
	{
		if (!ispr[i])
		{
			primes[pcnt++] = i;
			for (int j = i << 1; j < N; j += i)
			{
				ispr[j] = true;
			}
		}
	}
}

bool is_prime(int x)
{
	int sqx = sqrt((double)x) + 1;
	for (int i = 0; primes[i] < sqx; ++i)
	{
		if (!(x % primes[i]))
		{
			return false;
		}
	}
	return true;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章