uva10006 Carmichael Numbers(卡邁克爾數+素數打表)
題意:判斷一個數是否是卡邁克爾數。
這題做的我真是峰迴路轉啊。。
首先本來是想看著《挑戰》複習下快速冪,結果這題根本用不到。
剛開始看到x^n≡x(mod n)老實說把我嚇了一跳,一個數餘n怎麼會搞出一個這麼大的數。想了半天一度懷疑人生,去翻題解,結果主流都是相當於求解x≡x^n(mod n),就以為是不是書中印錯了。直到後來看到了卡邁克爾數的定義:
我擦嘞原來人家真的是這麼定義的,再往下翻好像和費馬小定理類似。。什麼??費馬小定理??好像前幾天看過沒看懂。。
是的和費馬小定理一毛一樣。。
好吧,看來書是對的,可是還是不能說明這個式子的不合理性呀。
直到看見同餘式的定義:
原來b^(n-1)-1能被n整除就行。。同餘式的概念沒理解。。這下真的懷疑人生了。。
問題又來了,怎麼算出整除結果呢?沒錯這就是卡邁克爾數的難度,是否是卡邁克爾數的公式要自己推啊,現在還沒有最標準的解,要不怎麼會有餘建春這種風靡一時的事蹟。。
我們再看一眼題:
用自己吃奶的英語翻譯,人家先是給了一個式子,然後說如果這個數通過了費馬測試(後來驗證這不是費馬測試的式子,只是打錯了而已)就是可靠性高的。但是很不幸!有一些不是素數的仍然通過了費馬測試,這些書就叫卡邁克爾數。這個問題就是讓你寫個程式判斷是否是卡邁克爾數。
至少可以肯定不是按照給出的這個式子解了,和這個式子無關。
掃了一眼網上的題解,感覺也就這個比較正確:大牛orz
主要給出的是一個判別法,很有價值:
不過這大牛題解第一句話就沒看懂,什麼“根據考塞特判別法,我們只需要求≤maxn/3的素數”,為毛要除啊聲淚俱下。。
索性自己按照著定理來了一遍,雖然時間多一點,不過感覺更容易懂。
順便體驗了一把uva的龜速:(真正體驗到了時差,我是晚上做的)
同時也向餘建春表示敬意,居然真的有人閒的沒事研究這種問題,我這渣渣望其項背啊。。
哎,又一個題做了一天,這種題下次遇到放到以後做吧,密碼學也許研究生才學,不過現在只是想爭取學的機會啊,別越級打怪了。。
。。。
最後還有一個問題,那些用快速冪過的連公式都沒用對,到底是怎麼過的??
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; typedef long long ll; const int N = 66000; int prime[N], num[N], cnt = 0; void prime_table() { memset(prime, 1, sizeof(prime)); for(int i = 2; i <= N; i++) { if(prime[i]) { for(int j = i+i; j <= N; j+=i) prime[j] = 0; } } } void choose_prime() { for(int i = 2; i <= N; i++) if(prime[i]) num[cnt++] = i; } int main() { prime_table(); choose_prime(); // freopen("in.txt", "r", stdin); int n, flag; while(~scanf("%d", &n)) { flag = 1; if(n == 0) break; if((!prime[n]) && (n%2==1)) { for(int i = 0; num[i] < n; i++) { if(n%num[i] == 0) { if(n%(num[i]*num[i])==0 || (n-1)%(num[i]-1)) { flag = 0; } } } } else { flag = 0; } if(flag) printf("The number %d is a Carmichael number.\n", n); else printf("%d is normal.\n", n); } return 0; }