快速幂(python实现)

前言

使用快速幂的原因,针对高次幂计算,如果使用循环遍历的方法,时间开销比较大eg:8^10000000000 而使用快速幂的方法可以在O(log(次幂))的复杂度内完成。

示例

import time
start=time.time()
p=1000000007
def quick_count(a,b):
    sum=1
    while b!=0:
        if b&1:
            sum=sum*a%p
        b>>=1
        a*=a#注意是x自身,容易写成x2, x2对应到阶乘下+1而非x2
    return sum
print(quick_count(2,10000000))
print(time.time()-start)

快速幂(python实现)_第1张图片
说明eg:2^8 8=>1000

2^8=>((2^4^2))
(((2^2^2^2)
迭代过程:
2 (2)^2 (2^2)^2 (2^2^2)^2

对比一般遍历程序:

import time
start=time.time()
p=1000000007
def quick_count(a,b):
    sum=1
    for i in range(0,b):
        sum=sum*a%p
    return sum
print(quick_count(2,10000000))
print(time.time()-start)

快速幂(python实现)_第2张图片
拓展:矩阵快速幂
快速幂需要满足结合律即我们想要的数据可以拆分成多个相同底项的乘积
eg:2^8 => 2^4* 2^4
根据这个特点,我们知道矩阵乘法不满足交换律,但是其满足结合律,所以通过矩阵快速幂求到矩阵的高次幂
eg:求斐波拉契数列,快速求某一项
根据
F[n]=F[n-1]+F[n-2]
F[n+1]=F[n]+F[n-1]

可得


F[n+1]=[0 1	 *F[n]
		1 1]
由此得F[n]=[0 1,1 1]^n*F[0]

再扩展:求斐波拉契数列的前N项和
这时可以构造

F[n]=[f(n),f(n+1),s(n)]
F[n+1]=[f(n+1),f(n+2),s[n+1)]
可得
矩阵为:[[0,1,0][1,1,1],[0,0,1]]
l=input().split(' ')
a=int(l[0])
m=int(l[1])
x=[[0,1,0],[1,1,1],[0,0,1]]
res = [[1, 0, 0],[0, 1, 0],[0, 0, 1]]
def get(mid,a,b):
    sum=0
    for i in range(0,3):
        sum=(sum+mid[a][i]*x[i][b])%m
    return sum%m
def chen(mid):
    end=[]
    for i in range(0,3):
        check=[]
        for j in range(0,3):
            check.append(get(mid,i,j))
        end.append(check)
    for i in range(0,3):
        mid[i]=end[i]

def quick(n):#n-1
    global res
    while n!=0:
        if n&1==1:
            chen(res)
        chen(x)
        n>>=1
        
quick(a-1)

print((res[0][2]+res[1][2]+res[2][2])%m)

矩阵快速幂的典型应用就是斐波那契数列求N项数据或者前N项和…
使用矩阵快速幂的地方一般是具有递推关系的式子,eg:这里的斐波拉契数列,将前后项抽象为一项,并使用矩阵表示他们之间的关系
eg:[fn+2,fn+1]=[fn+1,fn]*[[1,1],[1,0]] (因为fn+2=fn+1+fn,fn+1=fn+1)

a=input().split(' ')
n=int(a[0])
m=int(a[1])
import copy
check=[[1,1],[1,0]]
def get(check,check1,l,r):#用于计算矩阵乘法中的每一项
    global m
    sum=0
    for j in range(0,2):
        sum+=check[l][j]*check1[j][r]%m
    return sum
def chen():#用于得到结果矩阵
    global check
    mid=[[0,0],[0,0]]
    for i in range(0,2):
        for j in range(0,2):
            mid[i][j]=get(check,check,i,j)
    check=copy.copy(mid)
ans=[[1,0],[0,1]]
def mon():
    global ans
    mid=[[0,0],[0,0]]
    for i in range(0,2):
        for j in range(0,2):
            mid[i][j]=get(ans,check,i,j)
    ans=mid.copy()
while n!=0:
    if n&1:
        mon()
    chen()
    n>>=1
print((ans[0][0]+ans[1][0]-1)%m)

你可能感兴趣的:(python,快速幂)