快速幂

快速幂的一般格式为:给定三个正整数 a a a b b b m m m,求 a b % m a^b\%m ab%m
如果按照时间复杂度为 O ( b ) O(b) O(b)的写法,在 b b b 超过 1 0 8 10^8 108时就很容易超时,因此需要引入快速幂。

递归写法

快速幂基于以下两个条件:

  1. 如果 b b b 是奇数,那么有 a b = a ∗ a b − 1 a^b=a*a^{b-1} ab=aab1
  2. 如果 b b b 是偶数,那么有 a b = a b / 2 ∗ a b / 2 a^b=a^{b/2}*a^{b/2} ab=ab/2ab/2

对于奇数的情况总可以在下一步时转化为偶数,而偶数的情况总可以在下一步减小一半,这样在进行对数级别的次数转换后,就可以把 b b b 变成0,而所有的正整数的0次幂都是1。
因此,就可以得到时间复杂度为 O ( l o g b ) O(logb) O(logb)的快速幂递归写法:

typedef long long LL;
LL binaryPow(LL a, LL b, LL m) {
	if(b == 0) return 1;
	else if(b & 1) return a * binaryPow(a,b-1,m) % m;
	else {
		LL tmp = binaryPow(a,b/2,m) % m;
		return tmp * tmp % m;
	}
}

迭代写法

对于 a b a^b ab来说,如果把 b b b写成二进制,那么 b b b就可以写成若干二次幂之和。
例如: 13 13 13的二进制是 1101 1101 1101,那么 13 = 2 3 + 2 2 + 2 0 = 8 + 4 + 1 13=2^3+2^2+2^0=8+4+1 13=23+22+20=8+4+1,所以 a 13 = a 8 + 4 + 1 = a 8 ∗ a 4 ∗ a 1 a^{13}=a^{8+4+1}=a^8*a^4*a^1 a13=a8+4+1=a8a4a1
因此可以得到计算 a b a^b ab的思路:遍历 b b b的二进制的每一位,注意到序列 a 2 i 、 ⋅ ⋅ ⋅ 、 a 8 、 a 4 、 a 2 、 a 1 a^{2^i}、···、a^8、a^4、a^2、a^1 a2ia8a4a2a1的前一项总是后一项的平方,所以在编程时,可以每次都把 a i + 1 a^{i+1} ai+1变为 a i a^i ai的平方,如果当前位为1,则乘上当前的 a i a^i ai

typedef long long LL;
LL binaryPow(LL a,LL b,LL m) {
	LL ans = 1;
	while(b > 0) {
		//如果当前二进制位是1就累积上a
		if(b & 1) ans = ans * a % m;
		//令a平方
		a = a * a % m;
		//b的二进制右移一位
		b >>= 1;
	}
	return ans;
}

两个细节

还需要注意两个细节:

  1. 如果初始时 a a a大于等于 m m m,那么需要在进入函数前就让 a a a m m m取模。
  2. 如果 m m m为1,可以直接在函数外部特判为0,不需要计算,因为等于1取模一定为0。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值