问题
求 a b a^b ab, 为了简单起见, 假定 b ≥ 0 且 b 为 整 数 b\ge0 且b为整数 b≥0且b为整数.
朴素求解方法
这个问题很简单, 最简单的想法, a自乘b次即可, 也就是所谓的朴素求解方法:
int pow_naive(int a, int b) {
int ret = 1;
while (b--) {
ret *= a;
}
return ret;
}
上述方法时间复杂度为 O ( n ) O(n) O(n).
快速幂求解
而"快速幂"方法可以将时间复杂度提升到
O
(
log
n
)
O(\log n)
O(logn), 它基于这样的想法:
求
a
b
a^b
ab, 将b展开为二进制表达, 如当b=13时, 有:
b
=
(
1101
)
2
=
1
×
2
0
+
0
×
2
1
+
1
×
2
2
+
1
×
2
3
b = (1101)_2 = 1 \times 2^0 + 0 \times 2^1 + 1 \times 2^2 + 1 \times 2^3
b=(1101)2=1×20+0×21+1×22+1×23
a
b
=
a
2
0
+
0
+
2
2
+
2
3
=
a
2
0
×
a
2
2
×
a
2
3
a^b = a^{2^0 + 0 + 2^2 + 2^3} = a^{2^0} \times a^{2^2} \times a^{2^3}
ab=a20+0+22+23=a20×a22×a23
代码如下:
int pow_fast(int a, int b) {
int ret = 1;
int base = a;
while (b) {
if (b & 1) { // 当前b最低位为1, 比如 1101最右边的1
ret *= base;
}
b >>= 1;
base *= base;
}
return ret;
}
应用示例
可以看一个相关的应用来体会一下用法:
杭电 快速幂模基础板题
题目简单描述为:
1
≤
N
≤
1
,
000
,
000
,
000
,
求
N
N
的
最
后
一
位
数
1\le N \le 1,000,000,000, 求N^N的最后一位数
1≤N≤1,000,000,000,求NN的最后一位数.
简单分析下:
显然, 直接算太大, 会整型溢出. 假定结果为M, 最后一位数不就是 M%10嘛.
其实这就是典型的快速幂取模问题.
要使用快速幂取模来解决上述问题, 需要以下公式:
a
b
m
o
d
  
c
=
(
a
m
o
d
  
c
)
b
m
o
d
  
c
a^b \mod c = (a \mod c)^b \mod c
abmodc=(amodc)bmodc
证明如下:
-
首先证明:
a b m o d    c = ( ( a m o d    c ) × ( b m o d    c ) ) m o d    c ab \mod c = ((a \mod c) \times (b \mod c)) \mod c abmodc=((amodc)×(bmodc))modc证明过程:
a m o d    c = r 1 ⇒ a = q 1 c + r 1 b m o d    c = r 2 ⇒ b = q 2 c + r 2 a b m o d    c = ( q 1 c + r 1 ) ( q 2 c + r 2 ) m o d    c = [ q 1 q 2 c 2 + r 1 r 2 + ( q 1 r 2 + q 2 r 1 ) c ] m o d    c = r 1 r 2 m o d    c = ( ( a m o d    c ) × ( b m o d    c ) ) m o d    c a \mod c = r_{1} \Rarr a = q_{1}c + r_{1} \\ b \mod c = r_{2} \Rarr b = q_{2}c + r_{2} \\ \begin{aligned} ab \mod c &= (q_{1}c + r_{1})(q_{2}c + r_{2}) \mod c \\ &= [q_{1}q_{2}c^2 + r_{1}r_{2} + (q_{1}r_{2} + q_{2}r_{1})c] \mod c \\ &= r_{1}r_{2} \mod c \\ &= ((a \mod c) \times (b \mod c)) \mod c \end{aligned} amodc=r1⇒a=q1c+r1bmodc=r2⇒b=q2c+r2abmodc=(q1c+r1)(q2c+r2)modc=[q1q2c2+r1r2+(q1r2+q2r1)c]modc=r1r2modc=((amodc)×(bmodc))modc
证毕.
也就是说: 积的余 = 余的积的余 -
再证明:
a b m o d    c = ( a m o d    c ) b m o d    c a^b \mod c = (a \mod c)^b \mod c abmodc=(amodc)bmodc证明过程:
a b m o d    c = ( a × a b − 1 ) m o d    c = [ ( a m o d    c ) × ( a b − 1 m o d    c ) ] m o d    c = [ ( a m o d    c ) × ( a m o d    c ) × ( a b − 2 m o d    c ) ] m o d    c = . . . = ( a m o d    c ) b m o d    c \begin{aligned} a^b \mod c &= (a \times a^{b-1}) \mod c \\ &= [(a \mod c) \times (a^{b-1} \mod c)] \mod c \\ &= [(a \mod c) \times (a \mod c) \times (a^{b - 2} \mod c)] \mod c \\ &= ... \\ &= (a \mod c)^{b} \mod c \end{aligned} abmodc=(a×ab−1)modc=[(amodc)×(ab−1modc)]modc=[(amodc)×(amodc)×(ab−2modc)]modc=...=(amodc)bmodc
有了这个理论, 代码就不难了:
// 快速幂取模 模板代码
int pow_fast_tpl(int a, int b, int c) {
int ret = 1;
int base = a % c;
while (b) {
if (b & 1) {
ret = (ret * base) % c;
}
base = (base * base) % c;
b >>= 1;
}
return ret;
}
上述代码中, 令a=b=N, c = 10即可求出答案.
上述代码也可以作为"快速幂取模"的模板.
参考
欢迎补充指正!