1. 程式人生 > >uva10006 Carmichael Numbers(卡邁克爾數+素數打表)

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