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
*/
本文探讨了Carmichael数的定义及检测方法,通过枚举和模幂运算优化,实现了一个判断给定合数是否为Carmichael数的算法,并提供了完整的C++代码示例。
502

被折叠的 条评论
为什么被折叠?



