【算法学习笔记】33:快速幂的递归及循环实现

news/2025/1/16 14:58:25/

快速幂原理

要计算 a b a^b ab a b m o d p a ^ b~mod~p ab mod p,可以考虑用折半的方式缩小计算量。

例如要计算 2 13 2^{13} 213,只要计算 2 6 2^6 26乘以自己,再乘以一个多出来的2。

而要计算 2 6 2^6 26,只要计算 2 3 2^3 23乘以自己。

而要计算 2 3 2^3 23,只要计算 2 1 2^1 21乘以自己,再乘以一个多出来的2。

也就是每次把 b b b折半下取整,当 b b b是偶数时:
a b = a b 2 ⋅ a b 2 a^b = a^{\frac{b}{2}} \cdot a^{\frac{b}{2}} ab=a2ba2b
b b b是奇数时只要多乘以一个 a a a
a b = a b 2 ⋅ a b 2 ⋅ a a^b = a^{\frac{b}{2}} \cdot a^{\frac{b}{2}} \cdot a ab=a2ba2ba

如果需要对 p p p取模,只要在每一步乘法之后取模就可以了。

例题:AcWing 875. 快速幂

递归实现

从前面的原理很容易得到如下的递归实现。

#include <iostream>using namespace std;typedef unsigned long long ULL;ULL qmi(ULL a, ULL b, ULL p) {if (b == 1) return a % p;ULL res = qmi(a, b >> 1, p);res = res * res % p;if (b & 1) res = res * a % p;return res;
}int main() {int t; cin >> t;while (t -- ) {ULL a, b, p; cin >> a >> b >> p;cout << qmi(a, b, p) << endl;}return 0;
}

循环实现

从前面的原理理解循环实现不直观。可以考虑 b b b的二进制表示。例如 b = 0 b 1101 b = 0b1101 b=0b1101也就是 2 3 + 2 2 + 2 0 = 13 2^3+2^2+2^0=13 23+22+20=13,所以:

a 2 3 + 2 2 + 2 0 = a 2 3 ⋅ a 2 2 ⋅ a 2 0 a^{2^3 + 2^2 + 2^0} = a^{2^3} \cdot a^{2^2} \cdot a^{2^0} a23+22+20=a23a22a20

这正是因为 b b b的从低到高0、2、3二进制位置是1导致的。

又因为
( a 2 i ) 2 = a 2 i + 1 (a^{2^i})^2 = a^{2^{i+1}} (a2i)2=a2i+1
因此只需要循环的从最低位(第0位)开始,每次通过把 a a a和自己相乘计算一下 a 2 i a^{2^i} a2i,只要 b b b的相应二进制位置是1,就把这个数乘进res里即可。

#include <iostream>using namespace std;typedef unsigned long long ULL;ULL qmi(ULL a, ULL b, ULL p) {ULL res = 1;while (b) {if (b & 1) res = res * a % p;b >>= 1;a = a * a % p;}return res;
}int main() {int t; cin >> t;while (t -- ) {ULL a, b, p; cin >> a >> b >> p;cout << qmi(a, b, p) << endl;}return 0;
}

http://www.ppmy.cn/news/1563636.html

相关文章

数据结构与算法之链表: LeetCode 146. LRU 缓存 (Ts版)

LRU 缓存 https://leetcode.cn/problems/lru-cache/description/ 描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 ke…

容器技术全面攻略:Docker的硬核玩法

文章背景 想象一下&#xff0c;一个项目终于要上线了&#xff0c;结果因为环境配置不一致&#xff0c;测试服务器一切正常&#xff0c;生产环境却宕机了。这是开发者噩梦的开始&#xff0c;也是Docker救世主角色的登场&#xff01;Docker的出现颠覆了传统环境配置的方式&#…

【kubernetes】K8S节点状态的维护

1 节点状态 节点是K8S集群中的一类重要资源&#xff0c;节点的状态通常可以作为判断集群异常的重要手段。 为了展示节点在各方面的健康程度&#xff0c;在kubectl describe node k8s-master的输出结果中的Conditions部分可以查看k8s-master节点的一些状态数据&#xff1a; N…

【Linux】8.Linux基础开发工具使用(2)

文章目录 1. Linux编译器-gcc/g使用关于sudo1.1 背景知识1.2 gcc如何完成1.2.1 预处理(进行宏替换)1.2.2 编译&#xff08;生成汇编&#xff09;1.2.3 汇编&#xff08;生成机器可识别代码&#xff09;1.2.4 连接&#xff08;生成可执行文件或库文件&#xff09;1.2.5 总结 1.3…

OmniAudio-2.6B 简介与音频转文本实践

OmniAudio-2.6B 是一个基于 Transformer 的先进语音识别模型&#xff0c;具有强大的音频转文本能力。它利用大规模预训练和多语言支持&#xff0c;为离线和在线语音处理提供高精度的解决方案。 一、OmniAudio-2.6B 的原理 1. 核心技术 Transformer 架构&#xff1a;OmniAudio…

极客说|Azure AI Agent Service 结合 AutoGen/Semantic Kernel 构建多智能体解决⽅案

作者&#xff1a;卢建晖 - 微软高级云技术布道师 「极客说」 是一档专注 AI 时代开发者分享的专栏&#xff0c;我们邀请来自微软以及技术社区专家&#xff0c;带来最前沿的技术干货与实践经验。在这里&#xff0c;您将看到深度教程、最佳实践和创新解决方案。关注「极客说」&am…

ParcelFileDescriptor+PdfRenderer在Android渲染显示PDF文件

ParcelFileDescriptor 是一个非常重要的类&#xff0c;用于表示一个文件描述符&#xff08;File Descriptor&#xff0c;简称 FD&#xff09;&#xff0c;它可以让文件或数据通过进程间通信&#xff08;IPC&#xff09;进行共享。 1. 基本概念 ParcelFileDescriptor 是 andro…

【行空板K10】上传温湿度信息到EasyIoT平台

目录 引言 EasyIoT平台 程序编写 测试结果 结语 引言 今天测试一下使用行空板K10上传数据到EasyIoT平台。这个平台是DFRobot自由的物联网云平台&#xff0c;也是Mind支持的4个MQTT平台之一。 EasyIoT平台 EasyIoT平台的优点是非常简单&#xff0c;没有阿里云、华为云那…