题意:判断一个数是否是卡迈克尔数。
这题做的我真是峰回路转啊。。
首先本来是想看着《挑战》复习下快速幂,结果这题根本用不到。
刚开始看到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;
}