学习笔记:快速幂

快速幂

定义

快速幂,二进制取幂(Binary Exponentiation,也称平方法),是一个在 O(logn) 的时间内计算 an 的小技巧,而暴力的计算需要 O(n) 的时间。

这个技巧也常常用在非计算的场景,因为它可以应用在任何具有结合律的运算中。其中显然的是它可以应用于模意义下取幂、矩阵幂等运算,我们接下来会讨论。

解释

计算 an 次方表示将 na 乘在一起:an=a×a×an 个 a。然而当 a,n 太大的时侯,这种方法就不太适用了。不过我们知道:ab+c=abac,a2b=abab=(ab)2。二进制取幂的想法是,我们将取幂的任务按照指数的 二进制表示 来分割成更小的任务。

过程

首先我们将 n 表示为 2 进制,举一个例子:

313=3(1101)2=383431

因为 nlog2n+1 个二进制位,因此当我们知道了 a1,a2,a4,a8,,a2log2n 后,我们只用计算 Θ(logn) 次乘法就可以计算出 an

于是我们只需要知道一个快速的方法来计算上述 3 的 2k 次幂的序列。这个问题很简单,因为序列中(除第一个)任意一个元素就是其前一个元素的平方。

因此为了计算 313,我们只需要将对应二进制位为 1 的整系数幂乘起来就行了:

313=6561813=1594323

将上述过程说得形式化一些,如果把 n 写作二进制为 (ntnt1n1n0)2,那么有:

n=nt2t+nt12t1+nt22t2++n121+n020

其中 ni{0,1}。那么就有

an=(ant2t++n020)=an020×an121××ant2t

根据上式我们发现,原问题被我们转化成了形式相同的子问题的乘积,并且我们可以在常数时间内从 2i 项推出 2i+1 项。

这个算法的复杂度是 O(logn) 的,我们计算了 O(logn)2k 次幂的数,然后花费 O(logn) 的时间选择二进制为 1 对应的幂来相乘。

实现

P1226 【模板】快速幂

#include <cstdio>
#define int long long
using namespace std;
int a, b, p;
signed main(){
    scanf("%d %d %d", &a, &b, &p);
    printf("%d^%d mod %d=%d\n", a, b, p, qpow(a, b, p));
    return 0;
}
int qpow(int a, int b, int p){
    int res = 1;
    while(b > 0){
        if(b & 1)res *= a,es %= p;
        a *= a;a %= p;b >>= 1;
    }
    return res;
}
posted @   tsqtsqtsq  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示