caesiumlz96@gmail.com 2017/1/13
假设我们要计算 xa%p ,首先,不管是如下的哪一个算法,都基于如下事实:
(x∗y)%p=(x%p)⋅(y%p)%p
普通幂运算
令pow(x, a)为x的a次方取模,在普通指数运算中,我们利用n次循环来计算该值。时间复杂度为 O(n) 。
代码如下
int pow(int x, int a) {
int res = 1;
for (int i = 0; i < a; i++) res *= x, res %= mod;
return res;
}
快速幂
一种更快的方式是快速幂,分为递归快速幂和迭代快速幂
递归快速幂
其思想基于如下事实:
若
a
为奇数:
若
a
为偶数:
这样,我们每次只有缩小一半的计算量,时间复杂度降为 O(logn) 。
代码如下
int pow(int x, int a) {
if (a == 0) return 1;
int t = qp(x, a / 2) % mod;;
if (a & 1) return t * t * x % mod;
return t * t % mod;
}
迭代快速幂
我们可以将递归快速幂转化为迭代快速幂,时间复杂度仍然为 O(logn) ,但是其思想存在不同,迭代快速幂的思想是基于二进制分解的。
假如我们要计算 311 ,首先,我们将11转化为2进制形式即为 (1011)2 ,即 11=1⋅20+1⋅21+0⋅22+1⋅23 。
那么, 311 就转化成了 3(1⋅20+1⋅21+0⋅22+1⋅23) ,即 320⋅321⋅(0⋅322)⋅323 。即 31⋅(0⋅32)⋅34⋅38 ,由此,我们可以得到我们的迭代快速幂算法:
将我们的指数a进行二进制分解,从低位开始往高位计算:如果该位为1,那么结果res *= x;然后底数x平方,然后指数的二进制向高位走一位,即指数右移一位。
代码如下
int pow(int x, int a) {
int res = 1;
while (a) {
if (a & 1) res *= x, res %= mod;
x *= x; x %= mod;
a >>= 1;
}
return res;