欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > 【算法学习笔记】33:快速幂的递归及循环实现

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

2025/1/16 5:51:12 来源:https://blog.csdn.net/SHU15121856/article/details/145169364  浏览:    关键词:【算法学习笔记】33:快速幂的递归及循环实现

快速幂原理

要计算 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;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com