Programming Challenges 习题7.6.2

PC/UVa:110702/10006

Carmichael Numbers

一看到这道题就想起当年被1024位RSA支配的恐惧了,算一个明文算几个小时。

这题明显说了,对于给定的合数n,如果a ^ n mod n == a对于所有小于na成立,那么这个数就是Carmichael数,所以肯定是要从头到尾枚举才能算,能优化的方法就是在模幂运算上。

计算a ^ n mod n时,用的是每次平方,最后补全的方法。比如n13,依次计算1248次方模n的余数再存储,最后还剩5次方,根据5的二进制表示,拆为14的和。

过了之后去网上查了一下,有的博客说因为输入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
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值