把指数 b 按二进制拆成若干 2 的幂之和,逐位平方底数、只在为 1 的位累乘,用 O(log b) 次模乘求出 a^b mod p。
OJ: roj
题目 ID: 3000
难度:普及-
标签:数学位运算快速幂python
创建: 2026-10-01 09:05
更新: 2026-10-07 13:50
后置题目
roj 1643「一本通 6.5 例 3」Fibonacci 前 n 项和B 的 mat_pow 直接复用 A 教的「最低位为 1 就把 base 乘进 result、base 自平方、指数右移」这一快速幂迭代骨架(B 代码里 if n&1: result=mat_mul(result,base); base=mat_mul(base,base); n>>=1),只把标量乘法换成 2×2 转移矩阵乘法来求 T^{n+1},再叠加 A 未教的 S_n=f_{n+2}-1 恒等式与矩阵表示层。luogu P3390【模板】矩阵快速幂B 的 matrix_power 完全沿用 A 教的指数按二进制拆分与 base=base*base 循环,只是把整数乘法替换为矩阵乘法、1 替换为单位矩阵luogu P3197[HNOI2008] 越狱A 教的「指数按二进制拆分 + 底数逐位平方」快速幂,正是 B 在用补集计数得到 m^n - m*(m-1)^(n-1) 后必须调用的同一步幂运算,B 的 main.cpp 里 quick_pow 与 A 的 mod_pow 同构。
题目描述
给定整数 3 2 7,输出 2。约定
思路
把指数 result = 1 % p、base = a % p,
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 09:05
# update_at: 2026-10-01 09:05
import sys
def mod_pow(base: int, exponent: int, mod: int) -> int:
"""快速幂:把指数拆成二进制位,逐位平方底数,只把为 1 的那些位乘进结果。"""
result = 1 % mod # p = 1 时任何数取模都是 0,这一行顺手处理掉该边界
base %= mod # a 可能大于 p,先取模能让后续乘法保持在小整数范围内
while exponent:
if exponent & 1: # 最低位为 1:这一份 base^(2^k) 要乘进答案
result = result * base % mod
base = base * base % mod # base^(2^k) -> base^(2^(k+1))
exponent >>= 1 # 换到下一位
return result
def solve() -> None:
a, b, p = map(int, sys.stdin.buffer.read().split())
print(mod_pow(a, b, p))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 10:43
* update_at: 2026-10-06 10:43
*/
#include <iostream>
using namespace std;
typedef long long ll;
// 快速幂:把指数 exponent 按二进制拆分,逐位平方底数,只把为 1 的位乘进结果
ll mod_pow(ll base, ll exponent, ll mod) {
ll result = 1 % mod; // p = 1 时答案恒为 0,这一行一次处理掉该边界
base %= mod; // a 可能大于 p,先取模控制后续乘积范围
while (exponent > 0) {
if (exponent & 1) {
result = result * base % mod;
}
base = base * base % mod; // base^(2^k) -> base^(2^(k+1))
exponent >>= 1;
}
return result;
}
int main() {
ll a, b, p;
cin >> a >> b >> p;
cout << mod_pow(a, b, p) << "\n";
return 0;
}