最简单易懂快速幂算法

最简单易懂快速幂算法(fastpow)

看到其他文章写得太过于复杂,固然整理了一下思路,整理写了一篇简单易懂的快速幂算法讲解文章。

快速幂算法能够将O(n)降低到O(log n),快速幂所使用的二进制数拆分思想适用于矩阵的幂运算,线段树,树状数组等。
模板题:P1226 【模板】快速幂 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
同时为了减小运算过程中数字的大小,我们需要使用到
模运算的乘法性质
( a ∗ b ) % p = ( ( a % p ) ∗ ( b % p ) ) % p (a * b) \% p = ((a \% p) * (b \% p)) \% p (ab)%p=((a%p)(b%p))%p
这是模运算的一个基本性质,称为模运算的乘法性质。它表明,对于任意三个整数 a、b 和 p,它们的乘法对 p 取模的结果等于它们分别对 p 取模后的乘积再对 p 取模的结果。

这个性质的应用能够确保了每次乘法操作后结果在取模运算后不会溢出(缩小数字)。

应用前:

for _ in range(n):
   result *= a

大O(n)

应用后:

result=1
def power mod(a,n,p):
    in range(n):
        for result=(result*a)%p
        return result

范围缩小了,没有超出数据范围,但是速度还是太慢了

所以此时我们需要用上快速幂算法

假设我们要计算的是3^237

237拆分成二进制为11101101

利用二进制转十进制的性质,我们可以得知:
237 = 1 ∗ 2 7 + 1 ∗ 2 6 + 1 ∗ 2 5 + 0 ∗ 2 4 + 1 ∗ 2 3 + 1 ∗ 2 2 + 0 ∗ 2 1 + 1 ∗ 2 0 237 = 1*2^7 + 1*2^6 + 1*2^5 + 0*2^4 + 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0 237=127+126+125+024+123+122+021+120
再将二次幂展开:
237 = 1 ∗ 128 + 1 ∗ 64 + 1 ∗ 32 + 0 ∗ 16 + 1 ∗ 8 + 1 ∗ 4 + 0 ∗ 2 + 1 ∗ 1 237 = 1*128 + 1*64 + 1*32 + 0*16 + 1*8 + 1*4 + 0*2 + 1*1 237=1128+164+132+016+18+14+02+11
然后我们计算3^237的结果展开:
3 237 = ( 3 128 ) 1 ∗ ( 3 64 ) 1 ∗ ( 3 32 ) 1 ∗ ( 3 16 ) 0 ∗ ( 3 8 ) 1 ∗ ( 3 4 ) 1 ∗ ( 3 2 ) 0 ∗ ( 3 1 ) 1 3^{237} = (3^{128})^1 * (3^{64})^1 * (3^{32})^1 * (3^{16})^0 * (3^{8})^1 * (3^{4})^1 * (3^{2})^0 * (3^{1})^1 3237=(3128)1(364)1(332)1(316)0(38)1(34)1(32)0(31)1
然后通过观察,我们发现前者是后者的两倍,就比如:
( 3 128 ) = ( 3 64 ) ∗ ( 3 64 ) (3^{128}) = (3^{64}) * (3^{64}) (3128)=(364)(364)
也就是最终我们只需要进行十几次计算就能够计算出结果了,而不需要大O(n)次。

所以应用上快速幂之后,写法是:

result=1
while(n>0):
     if n%2 == 1: #取模操作是为了得到幂中的二进制的最低位
        res = res * a
     a = a*a #每次将a翻倍
     n //=n #除2
n(2)n&1aresult
111011011 3 1 3^1 31 3 1 3^1 31
11101100 3 2 = 3 1 2 3^2 = 3^{1^2} 32=312 3 1 3^1 31
1110111 3 4 = 3 2 2 3^4 = 3^{2^2} 34=322 3 1 ∗ 3 4 3^1 * 3^4 3134
111011 3 8 = 3 4 2 3^8 = 3^{4^2} 38=342 3 1 ∗ 3 4 ∗ 3 8 3^1 * 3^4 * 3^8 313438
11100 3 1 6 = 3 8 2 3^16 = 3^{8^2} 316=382 3 1 ∗ 3 4 ∗ 3 8 3^1 * 3^4 * 3^8 313438
1111 3 3 2 = 3 1 6 2 3^32 = 3^{16^2} 332=3162 3 1 ∗ 3 4 ∗ 3 8 ∗ 3 32 3^1 * 3^4 * 3^8 * 3^{32} 313438332
111 3 6 4 = 3 3 2 2 3^64 = 3^{32^2} 364=3322 3 1 ∗ 3 4 ∗ 3 8 ∗ 3 32 ∗ 3 64 3^1 * 3^4 * 3^8 * 3^{32}* 3^{64} 313438332364
11 3 128 = 3 6 4 2 3^{128} = 3^{64^2} 3128=3642 3 1 ∗ 3 4 ∗ 3 8 ∗ 3 32 ∗ 3 64 ∗ 3 128 3^1 * 3^4 * 3^8 * 3^{32} * 3^{64} * 3^{128} 3134383323643128

然后加上模运算减少数字大小:

def fast_pow_mode(a,n,p):
    result=1
    while(n>0):
        if n%2 == 1: 
           res = (res * a)%p
        a = (a*a)%p 
        n >>=1 #位运算跟除2一样的 

C++的写法:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int  a,b,p,result=1;
    cin>>a>>b>>p;
    while(b>0){
		if(b%2 == 1){
			result = (result*a)%p;
		}
		a = (a*a)%p;
		b = b/2; 
	}
	result = result%p;
	cout<<result<<endl;
    return 0;
};

参考:
2023年计算机设计大赛微课作品国赛二等奖——《快速幂算法》视频_哔哩哔哩_bilibili

  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值