1.大数求余问题
在仅使用int32
类型存储的前提下,正确计算
x
a
x^a
xa对
p
p
p的求余(
x
a
x^a%p
xa)的值。
P.S. 虽然在Python中不会涉及到大数问题(Python中没有int32类型,若要使用32位整型,需要x = x & 0xffffffff
),但也在此记录下。
解题思路
首先,我们有3个余数定理:
- ( a + b ) % c = ( a % c + b % c ) % c (a+b)\%c=(a\%c+b\%c)\%c (a+b)%c=(a%c+b%c)%c
- a % c = ( a % c ) % c a\%c=(a\%c)\%c a%c=(a%c)%c
- ( a b ) % c = [ ( a % c ) ( b % c ) ] % c (ab)\%c=[(a\%c)(b\%c)]\%c (ab)%c=[(a%c)(b%c)]%c
1.1循环求余 O ( n ) O(n) O(n)
由定理3我们可以推知:
x
a
%
p
=
[
(
x
a
−
1
%
p
)
(
x
%
p
)
]
%
p
=
[
(
x
a
−
1
%
p
)
x
]
%
p
x^{a}\%p=[(x^{a-1}\%p)(x\%p)]\%p=[(x^{a-1}\%p)x]\%p
xa%p=[(xa−1%p)(x%p)]%p=[(xa−1%p)x]%p
由此,我们可以利用循环操作依次求得
x
1
,
x
2
,
⋯
,
x
a
x^1,x^2,\cdots,x^a
x1,x2,⋯,xa对
p
p
p的余数,保证每轮中间求得的余数都在32位整数范围内。
def remainder(x,a,p):
"""
rem = x^a % p
"""
rem = 1
for _ in range(a):
rem = (rem * x) % p
return rem
1.2.快速幂求余 O ( log n ) O(\log n) O(logn)
由定理3可知:
x
a
%
p
=
(
x
2
)
a
/
2
%
p
=
(
x
2
%
p
)
a
/
2
%
p
x^a\%p=(x^2)^{a/2}\%p=(x^2\%p)^{a/2}\%p
xa%p=(x2)a/2%p=(x2%p)a/2%p
又由于
a
a
a为奇数时
a
/
2
a/2
a/2不为整数,故奇偶分开计算:
x
a
%
p
=
{
(
x
2
%
p
)
a
/
2
%
p
,
a
为
偶
数
[
(
x
%
p
)
(
x
a
−
1
%
p
)
]
%
p
=
[
x
(
x
2
%
p
)
a
/
/
2
]
%
p
,
a
为
奇
数
x^a\%p=\left\{ \begin{aligned} &(x^2\%p)^{a/2}\%p,~~~a为偶数\\ &[(x\%p)(x^{a-1}\%p)]\%p=[x(x^2\%p)^{a//2}]\%p,~~~a为奇数\\ \end{aligned} \right.
xa%p={(x2%p)a/2%p, a为偶数[(x%p)(xa−1%p)]%p=[x(x2%p)a//2]%p, a为奇数
def remainder(x,a,p):
"""
rem = x^a % p
"""
rem = 1
while a:
if a & 1: rem = (rem * x) % p
x = x ** 2 % p
a //= 2
return rem
2.快速幂问题
快速求解 x n x^n xn
解题思路
设函数
f
(
x
,
n
)
f(x,n)
f(x,n)求解
x
a
x^a
xa,我们可以知道:
x
a
=
(
x
a
/
2
)
2
x^a=(x^{a/2})^2
xa=(xa/2)2,则:
f
(
x
,
n
)
=
f
(
x
,
n
/
2
)
×
f
(
x
,
n
/
2
)
f(x,n)=f(x,n/2)\times f(x,n/2)
f(x,n)=f(x,n/2)×f(x,n/2)
又注意到
n
n
n为奇数时
n
/
2
n/2
n/2不为整数,故有:
f ( x , n ) = { f ( x , n / 2 ) × f ( x , n / 2 ) , n 为 偶 数 f ( x , n − 1 ) × x , n 为 奇 数 f(x,n)=\left\{ \begin{aligned} &f(x,n/2)\times f(x,n/2),~~~n为偶数\\ &f(x,n-1)\times x,~~~n为奇数 \end{aligned} \right. f(x,n)={f(x,n/2)×f(x,n/2), n为偶数f(x,n−1)×x, n为奇数
- 递归基: n = 0 n=0 n=0时,返回1; n = − 1 n=-1 n=−1时,返回 1 / x 1/x 1/x
- 依据公式进行尾递归即可
def myPow(x,n):
"""
res = x^n
"""
if n == 0: return 1
if n == -1: return 1/x
if x & 1 == 0:
tmp = myPow(x,n//2)
return tmp*tmp
else:
return myPow(x,n-1)*x