PC/UVa:110702/10006
一看到这道题就想起当年被1024
位RSA支配的恐惧了,算一个明文算几个小时。
这题明显说了,对于给定的合数n
,如果a ^ n mod n == a
对于所有小于n
的a
成立,那么这个数就是Carmichael数,所以肯定是要从头到尾枚举才能算,能优化的方法就是在模幂运算上。
计算a ^ n mod n
时,用的是每次平方,最后补全的方法。比如n
为13
,依次计算1
、2
、4
、8
次方模n
的余数再存储,最后还剩5
次方,根据5
的二进制表示,拆为1
和4
的和。
过了之后去网上查了一下,有的博客说因为输入n
的范围很小,可以直接判断是不是Carmichael数输出就行。如果只能这么玩的话那可真是够了。
#include <iostream>
#include <vector>
using namespace std;
bool Prime(unsigned int n)
{
if(n == 2) return true;
if(n % 2 == 0) return false;
for (unsigned int i = 3; i * i <= n; i += 2)
{
if (n % i == 0) return false;
}
return true;
}
void Carmichael(unsigned int n)
{
//判断是否是合数
if (Prime(n)){
cout << n << " is normal." << endl;
return;
}
for (unsigned int i = 2; i < n; i++)
{
//(a ^ n) mod n
unsigned int a = i, j;
vector<unsigned int> viRem(1, a);
for (j = 2; j < n; j <<= 1)
{
a = (a * a) % n;
viRem.push_back(a);
}
j >>= 1;
j = n - j;
for (int k = 0; j != 0; k++, j >>= 1)
{
if ((j & 0x1) == 1) a = (a * viRem[k]) % n;
}
if(a != i){
cout << n << " is normal." << endl;
return;
}
}
cout << "The number " << n << " is a Carmichael number." << endl;
return;
}
int main()
{
unsigned int n;
while (cin >> n){
if (n == 0) break;
Carmichael(n);
}
return 0;
}
/*
1729
17
561
1109
431
0
*/