uva10006 Carmichael Numbers(卡迈克尔数+素数打表)


https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=12&page=show_problem&problem=947

题意:判断一个数是否是卡迈克尔数。


这题做的我真是峰回路转啊。。

首先本来是想看着《挑战》复习下快速幂,结果这题根本用不到。


刚开始看到x^n≡x(mod n)老实说把我吓了一跳,一个数余n怎么会搞出一个这么大的数。想了半天一度怀疑人生,去翻题解,结果主流都是相当于求解x≡x^n(mod n),就以为是不是书中印错了。直到后来看到了卡迈克尔数的定义:

uva10006 Carmichael Numbers(卡迈克尔数+素数打表)_第1张图片

我擦嘞原来人家真的是这么定义的,再往下翻好像和费马小定理类似。。什么??费马小定理??好像前几天看过没看懂。。

是的和费马小定理一毛一样。。

好吧,看来书是对的,可是还是不能说明这个式子的不合理性呀。

直到看见同余式的定义:

uva10006 Carmichael Numbers(卡迈克尔数+素数打表)_第2张图片

原来b^(n-1)-1能被n整除就行。。同余式的概念没理解。。这下真的怀疑人生了。。

问题又来了,怎么算出整除结果呢?没错这就是卡迈克尔数的难度,是否是卡迈克尔数的公式要自己推啊,现在还没有最标准的解,要不怎么会有余建春这种风靡一时的事迹。。


我们再看一眼题:

uva10006 Carmichael Numbers(卡迈克尔数+素数打表)_第3张图片

用自己吃奶的英语翻译,人家先是给了一个式子,然后说如果这个数通过了费马测试(后来验证这不是费马测试的式子,只是打错了而已)就是可靠性高的。但是很不幸!有一些不是素数的仍然通过了费马测试,这些书就叫卡迈克尔数。这个问题就是让你写个程序判断是否是卡迈克尔数。

至少可以肯定不是按照给出的这个式子解了,和这个式子无关。


扫了一眼网上的题解,感觉也就这个比较正确:大牛orz

主要给出的是一个判别法,很有价值:


不过这大牛题解第一句话就没看懂,什么“根据考塞特判别法,我们只需要求≤maxn/3的素数”,为毛要除啊声泪俱下。。

索性自己按照着定理来了一遍,虽然时间多一点,不过感觉更容易懂。

顺便体验了一把uva的龟速:(真正体验到了时差,我是晚上做的)


同时也向余建春表示敬意,居然真的有人闲的没事研究这种问题,我这渣渣望其项背啊。。

哎,又一个题做了一天,这种题下次遇到放到以后做吧,密码学也许研究生才学,不过现在只是想争取学的机会啊,别越级打怪了。。


。。。


最后还有一个问题,那些用快速幂过的连公式都没用对,到底是怎么过的??

uva10006 Carmichael Numbers(卡迈克尔数+素数打表)_第4张图片


#include 
#include 
#include 

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


你可能感兴趣的:(其他oj,数论-组合数学)