思路:对b用二进制表示,分开操作防止溢出。
对b用二进制表示:
b
=
b
0
∗
2
0
+
b
1
∗
2
1
+
b
2
∗
2
2
+
.
.
.
+
b
n
∗
2
n
,
b
i
=
0
o
r
1
,
i
=
0
,
.
.
,
n
b=b_0*2^0+b_1*2^1+b_2*2^2+...+b_n*2^n,b_i=0 \ or\ 1,i=0,..,n
b=b0∗20+b1∗21+b2∗22+...+bn∗2n,bi=0 or 1,i=0,..,n
a
b
=
a
b
0
∗
2
0
+
b
1
∗
2
1
+
b
2
∗
2
2
+
.
.
.
+
b
n
∗
2
n
=
a
b
0
∗
2
0
∗
a
b
1
∗
2
1
∗
.
.
.
∗
a
b
n
∗
2
n
a^b=a^{b_0*2^0+b_1*2^1+b_2*2^2+...+b_n*2^n}=a^{b_0*2^0}*a^{b_1*2^1}*...*a^{b_n*2^n}
ab=ab0∗20+b1∗21+b2∗22+...+bn∗2n=ab0∗20∗ab1∗21∗...∗abn∗2n
a的b次方对p取模,每次累乘
a
b
i
∗
2
i
a^{b_i*2^i}
abi∗2i后立即取模,这样不会溢出。
a
∗
b
=
a
∗
(
b
0
∗
2
0
+
b
1
∗
2
1
+
b
2
∗
2
2
+
.
.
.
+
b
n
∗
2
n
)
=
a
∗
b
0
∗
2
0
+
a
∗
b
1
∗
2
1
+
.
.
.
+
a
∗
b
n
∗
2
n
a*b=a*(b_0*2^0+b_1*2^1+b_2*2^2+...+b_n*2^n)=a*b_0*2^0+a*b_1*2^1+...+a*b_n*2^n
a∗b=a∗(b0∗20+b1∗21+b2∗22+...+bn∗2n)=a∗b0∗20+a∗b1∗21+...+a∗bn∗2n
a乘b对p取模,每次累加
a
∗
b
i
∗
2
i
a*b_i*2^i
a∗bi∗2i后立即取模,这样不会溢出。
时间复杂度,两者都是b拆开后的项数, O ( ⌊ l o g 2 b ⌋ + 1 ) ≈ O ( l o g b ) O(\lfloor{log_2b}\rfloor+1) \approx O(logb) O(⌊log2b⌋+1)≈O(logb)
a = 4
b = 3
p = 3
def quick_power(a, b, p):
tmp,sum = 1, 1
while b:
tmp = tmp*a%p
if b&1:
sum = sum*tmp%p
b >>= 1
return sum
print(quick_power(a, b, p))
def quick_mul(a, b, p):
sum, tmp = 0, 1
flag = False
while b:
if not flag:
tmp *= 1
flag = True
else:
tmp = tmp*2%p
if b&1:
sum = (sum + a*tmp)%p
b >>= 1
return sum
print(quick_mul(a, b, p))