快速幂(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)

在这里插入图片描述
说明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)

在这里插入图片描述
拓展:矩阵快速幂
快速幂需要满足结合律即我们想要的数据可以拆分成多个相同底项的乘积
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)
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看不见的罗辑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值