Jerry's Blog

Back

快速幂用于在 O(logn)O(\log n) 的速度计算一个数的 nn 次幂.

P1226 【模板】快速幂

题目描述#

给你三个整数 a,b,pa,b,p,求 abmodpa^b \bmod p

输入格式#

输入只有一行三个整数,分别代表 a,b,pa,b,p

输出格式#

输出一行一个字符串 a^b mod p=s,其中 a,b,pa,b,p 分别为题目给定的值, ss 为运算结果.

数据范围#

对于 100%100\% 的数据,保证 0a,b<2310\le a,b < 2^{31}a+b>0a+b>02p<2312 \leq p \lt 2^{31}

快速幂使用倍增的思想.

对于任意一个指数 bb,将其用二进制表示,可以拆解为 2a1+2a2++2an2^{a_1} + 2^{a_2} + \cdots + 2^{a_n} 的形式,其中 aia_i 为互不相同的非负整数.不难得出,设 bb 二进制表示中的第 kk 位为 1,则所有 aia_i 和所有 k1k-1 对应相等.

根据幂的相关性质可知,ab=a2k1+2k2++2kn=a2k1×a2k2××a2kna^b=a^{2^{k_1} + 2^{k_2} + \cdots + 2^{k_n}}=a^{2^{k_1}}\times a^{2^{k_2}}\times \cdots \times a^{2^{k_n}},即指数的二进制表示中,所有位数值为 1 的位,记该位的权值为 pp,答案就是 piPap\sum_{p_i \in P}a^p,其中,PP 是所有满足要求的 pp 的取值.

例如,对于 a=3a=3b=10b=10 的情况,由于 101010_{10} 的二进制为 101021010_2,其中,为 1 的位是右起第 2 位(对应权值为 221=22^{2-1}=2)和右起第四位(对应权值 241=82^{4-1}=8),所以,P={2,8}P=\{2,8\}310=32×383^{10} = 3^2\times 3^8

因此,检查 bb 二进制中的每一位.并对于权值为 pp 的位,通过递推记录当前位的 apa^p ,若 bb 二进制的该位为 1,则将 apa^p 计入答案.如何通过递推记录?只需要在从权值为 pp 的一位转移到左边一位时,由于左边一位的权值是 2p2p,将 apa^p 平方为 a2pa^{2p} 即可.

可以写出基本流程:

  1. 检查 bb 二进制右起第一位是否为 1,若是,则将答案乘上 aa
  2. bb 左移一位,露出 bb 的二进制右起第二位.
  3. 由于 bb 左移了一位,所以目前 bb 右起第一位的权值翻了倍,需要让 aa 平方才能让权值指数也翻倍.
  4. 若当前 bb 大于等于 1,则回到步骤 1.

核心代码如下:

int exp = b; // 记录目前剩余的指数
int ans = 1; // 记录答案
int now = a; // 记录现在位的权值
while (exp >= 1) {
	if (exp % 2) // 如果当前位是1
		ans *= now; // 就将当前位的权值记录答案
	exp /= 2; // 指数右移一位
	now *= now; // 权值对应增加
}
cpp

此外,这道题还要注意取模和开 long long

标程如下:

快速幂
https://blog.jerrylab.top/blog/other/fast-pow
Author Jerry
Published at 2026年4月11日