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;
}