挑戰程序設計競賽 2.6章習題 UVA - 10006 Carmichael Numbers

https://vjudge.csgrandeur.cn/problem/UVA-10006

 當今計算機科學的一個重要的領域就是密碼學。有些人甚至認爲密碼學是計算機科學中唯一重要的領域,沒有密碼學生命都沒有意義。
  阿爾瓦羅就是這樣的一個人,它正在設計一個爲西班牙雜燴菜飯加密的步驟。他在加密算法中應用了一些非常大的素數。
  然而確認一個非常大的數是不是素數並不是那麼簡單。一個費時的方法是用比這個數的平方根小的所有素數去除它,
  對於大整數來說,這樣一定會毀掉這個雜燴菜飯的。
  然而,一些很有信心耗時少的隨機測試存在,其中一個就是費馬測試。
  在2和n-1之間隨機選取一個數(n是我們要測試的數)。如果a n mod n = a 成立,n就可能是一個素數。
  如果一個數通過費馬測試很多次那麼它就很可能是一個素數。
  不幸的是,一些數不是素數但是它們依然能通過每一個比它小的數的費馬測試。這些數被稱作卡邁克爾數
  這道題要求你寫一個程序去測試給定的數是不是一個卡邁克爾數。
  完成了這個任務的隊伍有希望接受來自阿爾瓦羅的西班牙雜燴菜飯23333

Input
多組輸入,第一行給一個n (2 < n < 65000) 。n = 0 表示輸入結束並不需要處理
Output
對每組輸入,輸出它是不是卡邁克爾數,參考樣例。

Sample Input
1729
17
561
1109
431
0

Sample Output
The number 1729 is a Carmichael number.
17 is normal.
The number 561 is a Carmichael number.
1109 is normal.
431 is normal.

解答
題意是找出一些和素數性質類似,但是不是素數的卡米爾數。
對於一個數n, 如果2和n-1之間的數a(n是我們要測試的數)。a^n mod n = a 均成立,n就可能是一個素數。
如果n不是素數,他就是卡米爾數

那麼我們先打表 記錄數據範圍內所有的素數,然後保證n在表裏面,逐個檢測2和n-1 是否符合a^n mod n = a .
就可以判斷是不是卡米爾數了。 a^n使用快速冪計算。
代碼如下

#include <iostream>
#include <unordered_set>

using namespace std;


int n;
unordered_set<int> ss;
const int N = 65010;
int primes[N], cnt;
bool st[N];

void get_primes(int t) {
	for (int i = 2; i <= t; i++) {
		if (!st[i]) {
			primes[cnt++] = i;
			ss.insert(i);
		}
		for (int j = 0; primes[j] <= t / i; j++) {
			st[primes[j] * i] = true;
			if (i % primes[j] == 0) break;
		}
	}
}

int quickmi(long long a, long long b, long long m) {
	long long ans = 1;
	while (b) {
		if (b & 1) {
			ans = ans * a % m;
		}
		b >>= 1;
		a = a * a % m;
	}

	return ans;
}

void solve() {
	if (ss.count(n) != 0) {
		cout << n << " is normal." << endl;
		return;
	}

	for (int i = 2; i < n; i++) {
		if (quickmi(i, n, n) != i) {
			cout << n << " is normal." << endl;
			return;
		}
	}

	cout << "The number "<< n<< " is a Carmichael number." << endl;
	return;
}

int main()
{
	get_primes(N);
	while (cin >> n) {
		if (0 == n) break;
		solve();
	}

	return 0;
}

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