2 solutions

  • 1
    @ 2026-6-10 10:02:50

    快速幂 — 二进制拆分加速

    问题

    计算 abmodma^b \bmod m,其中 bb 最高可达 10910^9。如果直接循环 bb 次,O(b)O(b) 的时间复杂度必然 TLE

    怎么想?

    bb 写成二进制形式:

    $$b = (b_k b_{k-1} \dots b_1 b_0)_2 = b_0 \cdot 2^0 + b_1 \cdot 2^1 + \dots + b_k \cdot 2^k$$

    于是:

    $$a^b = a^{b_0 \cdot 2^0} \times a^{b_1 \cdot 2^1} \times \dots \times a^{b_k \cdot 2^k}$$

    其中每个 bi{0,1}b_i \in \{0, 1\}。当 bi=1b_i = 1 时,乘上对应的 a2ia^{2^i}bi=0b_i = 0 时跳过。

    a2ia^{2^i} 可以通过反复平方得到:(a2i1)2=a2i(a^{2^{i-1}})^2 = a^{2^i}

    这样只需要 O(logb)O(\log b) 次运算,b=109b=10^9log2b30\log_2 b \approx 30 次,比 10910^9 次循环快了三千多万倍

    位运算实现

    如何判断 bb 的二进制第 ii 位是 00 还是 11?—— 答案:位运算

    运算 含义 示例
    b & 1 bb 的最低位(第 00 位) 13 & 1 = 1
    b >>= 1 bb 右移一位(去掉最低位) 13 >> 1 = 6

    算法流程:

    1. b & 1 检查当前最低位,若为 11 则乘入答案
    2. a = a * a % m 计算下一次的基底(平方)
    3. b >>= 1 右移一位,继续处理下一个二进制位
    4. b == 0 时结束

    a=2,b=13a=2, b=13 为例:

    13=11012=23+22+2013 = 1101_2 = 2^3 + 2^2 + 2^0
    轮次 bb(二进制) b&1b \& 1 aa 的幂次 乘入? 答案
    1 1101 1 212^1 22
    2 110 0 222^2
    3 11 1 242^4 2×16=322 \times 16 = 32
    4 1 282^8 32×256=819232 \times 256 = 8192
    5 0 81928192

    213=81922^{13} = 8192,仅需 44 轮!

    复杂度

    • 时间O(logb)O(\log b),每次循环做常数次乘法和位运算
    • 空间O(1)O(1)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    ll fast_pow(ll a, ll b, ll m) {
        ll res = 1 % m;   // 注意 m 可能为 1
        a %= m;
        while (b) {
            if (b & 1)            // 最低位是 1 吗?
                res = (res * a) % m;
            a = (a * a) % m;      // 平方,准备下一位
            b >>= 1;              // 右移,处理下一个二进制位
        }
        return res;
    }
    
    int main() {
        ios::sync_with_stdio(false), cin.tie(NULL);
        ll a, b, m;
        cin >> a >> b >> m;
        cout << fast_pow(a, b, m) << '\n';
        return 0;
    }
    

    Information

    ID
    6
    Time
    1000ms
    Memory
    256MiB
    Difficulty
    2
    Tags
    # Submissions
    15
    Accepted
    7
    Uploaded By