Skip to content

快速幂

2021-07-31

快速幂

如何快速求 aba,bZ)?

递归写法

根据乘方公式 am+n=aman,有:

ab={ab/2ab/2b=2kab/2ab/2ab=2k+1,kZ
  • 边界条件:a0=1
  • 时间复杂度:O(logb)
cpp
typedef long long LL;

LL Pow(LL a, LL b) {
    if (!b) return 1; // 边界条件
    LL res = Pow(a, b / 2);
    if (b % 2 == 0)   // b 是偶数
        return res * res;
    else              // b 是奇数
        return res * res * a;
}

递推写法

b 在二进制下的第 k1,k2,k3, 位为 1,则 b=2k1+2k2+2k3+(kilogb)

举个例子,(14)10=(1011)2,二进制下 14 的第 0,1,3 位都为 1,那么 14=20+21+23

b=2k1+2k2+2k3+ 代入 ab

ab=a(2k1+2k2+2k3+)=a2k1a2k2a2k3 

扫描 b 的每个二进制位,如果第 k 位是 1,则将答案乘上 a2k

时间复杂度为 O(logb)

cpp
typedef long long LL;

LL Pow(LL a, LL b) {
    LL res = 1;
    while (b) {
        if (b % 2 == 1) // 二进制下该位为 1
            res *= a;
        a *= a, b /= 2;
    }
    return res;
}

更多时候,需要求对 m 取模的快速幂结果,那么需要全程取模:

cpp
typedef long long LL;

LL Pow(LL a, LL b, LL m) {
    LL res = 1;
    while (b) {
        if (b & 1) // 等价于 b % 2 == 1
            res = (res * a) % m;
        a = (a * a) % m;
        b >>= 2;
    }
    return res;
}