Carmichael Numbers——快速幂运算

Carmichael Numbers

我们把对任意的 1 < x < n 1 < x < n 1<x<n 都有 x n ≡ x ( m o d n ) x^n\equiv x(mod\quad n) xnx(modn)成立的合数 n n n称为Carmichael Number。对于给定的整数 n n n,请判断它是不是Carmichael Number。
 
限制条件

  • 2 < n < 65000 2 < n < 65000 2<n<65000
     样例输入
    样例1
输入
17 17 17
输出
No(17是素数)

样例2

输入
561 561 561
输出
Yes

样例3

输入
4 4 4
输出
No( 2 4 ≡ 0 ( m o d 4 2^4 \equiv0 (\quad mod4 240(mod4) )

题解
此题中,有 n n n 个待检查的书,如果每个数都按定义 O ( n ) O(n) O(n)复杂度来计算幂,则总的负责的为 O ( n 3 ) O(n^3) O(n3),时间复杂度太高,过不了。我们来介绍快速幂的方法。如果 n = 2 k n=2^k n=2k ,可以将其表示为:
x n = ( ( x 2 ) 2 ) ⋯ x^n=((x^2)^2)\cdots xn=((x2)2)
只要做 k 次平方运算就可以轻松求得。由此我们可以想到,先将 n 表示为 2 的幂次的和。(可以结合该数的二进制形式来理解)
n = 2 k 1 + 2 k 2 + 2 k 3 + ⋯ n=2^{k_1}+2^{k_2}+2^{k_3}+\cdots n=2k1+2k2+2k3+
就有
x n = x 2 k 1 x 2 k 2 x 2 k 3 ⋯ x^n=x^{2^{k_1}}x^{2^{k_2}}x^{2^{k_3}}\cdots xn=x2k1x2k2x2k3
只要在依次求出 x 2 i x^{2^i} x2i的同时进行计算就行了,最终得到 O ( l o g n ) O(logn) O(logn)计算快速幂运算的算法。
核心代码:

typedef long long ll;
ll res = 1;
while(n>0)
{
	if(n & 1) res = res * x % k;  // 如果二进制最低为为1,则乘上 x^(2^i)
	x = x * x % k;				 // 将 x 平方
	n >>= 1;
}
printf("%lld",res);

 

我们通过一个实例来消化一下:
x 22 = x 16 × x 4 × x 2 x^{22}=x^{16}\times x^{4} \times x^2 x22=x16×x4×x2
解释一下式子的来由:
因为,22 的二进制形式是 10110 (从最右边开始,第1位是第0位),我们看到“10110”该数的第1位、第2位、第四位都不为0,即代表,22 可以由 2 1 + 2 2 + 2 4 2^1+2^2+2^4 21+22+24来构成,这也就对应了上面的公式,同时也是对应了代码中的:

if(n & 1) res = res * x % k; 

当 n 的值每右移一位(n >>= 1),我们都判断一下,如果它的最低为上面是1,我们就乘上 x 2 i x^{2^i} x2i。至于为什么这样分步来对 k 来取模运算得到的答案是和结果相同的,可以去熟悉取模的基本运算规则(运算规则放在了文末)。
 
上面的程序还没有完全做完(我们只重点介绍快速幂的思想),还有加上一个素数判断的部分,判断素数可以打表也可以直接判断,最后如果不是素数,并且上面代码对 k 的取模运算等于 x 自身对 k 的取模运算,那么输出 Yes。
 
学完巩固题:P1226 【模板】快速幂||取余运算

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值