快速幂CSP-J

目录

💡 核心思想

快速幂在 $O(\log n)$ 时间内计算 $a^n \mod p$。核心是将指数按二进制分解:$a^n = a^{b_0 \cdot 2^0} \cdot a^{b_1 \cdot 2^1} \cdot \ldots$,其中 $b_i$ 是 $n$ 的二进制位。每次平方并按位累乘。

快速幂是竞赛中的"万金油"——数论题几乎都要用。代码只有几行但非常精妙:底数不断自平方,指数不断右移。如果当前位是 1 就把当前底数乘进答案。注意每步都要取模,防止溢出。

🎯 直觉理解

快速幂求 $a^b$,朴素循环乘 b 次是 $O(b)$,b 是 $10^{18}$ 就完蛋;快速幂只要 $O(log b)$。

原理:把指数拆成二进制。$b=13=1101_2$,$a^{13}=a^8 imes a^4 imes a^1$——只需要算 $a^1, a^2, a^4, a^8$(每次平方)四个数,乘起来即可。

代码三行核心:while(b){ if(b&1) ans=ans*a%M; a=a*a%M; b>>=1; }。每次循环:a 自己平方(对应二进制位权重翻倍),b 的当前最低位决定要不要乘进答案。配套记得取模防溢出。矩阵快速幂完全同理,把 a 换成矩阵、乘法换成矩阵乘法,用来加速线性递推(如斐波那契)。

📝 算法流程

  1. 初始化 ans = 1
  2. n 的每一位:如果为 1,ans *= a
  3. a = a * a(自平方)
  4. n >>= 1(右移一位)

$$a^n = \prod_{i: b_i = 1} a^{2^i} \pmod{p}$$

📊 复杂度分析

指标复杂度
时间$O(\log n)$
空间$O(1)$

💻 参考实现(C++)

C++ (C++17)
#include 
using namespace std;
typedef long long ll;
ll qpow(ll a, ll n, ll mod) {
    ll ans = 1; a %= mod;
    while (n) {
        if (n & 1) ans = ans * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ans;
}
int main() {
    ll a, n, p; cin >> a >> n >> p;
    cout << qpow(a, n, p) << endl;
    return 0;
}

⚠️ 常见坑点

每步都要取模,不要只在最后取

a 要先 %= mod

n = 0 时结果应为 1(但要考虑 0^0)

快速幂可以推广到矩阵乘法

📚 相关题目

题目来源难度备注
P1226 快速幂洛谷CSP-S快速幂模板
P1962 斐波那契数列洛谷CSP-S矩阵快速幂