【快速幂】快速幂简单分析

 快速幂:快速求 a ^ b % p(这三个数的数量级都可以为10^9)的问题,时间复杂度:O(logb)

首先要知道模运算有一个重要的规律:

(a * b) % p = (a % p * b % p) % p

由这个公式,可以将计算的过程分为三步:

①先分解出a^b 的一部分因数(具体是哪部分下文会分析);

②将这些因数分别对p取模得到一系列数;

③然后将这些数相乘的结果p取模即可得出结果。

在代码运行过程中,决定运算效率的关键就是如何快速分解出 a ^ b 的一部分因数,如果是分解成b个a,运算的时间复杂度就会高达O(b)。那么,有什么方式是既方便运算,又可以将a^b分解为足够少的因数呢?

此处使用的方法是将a^b分解为:\(k_0\) * \(a^{2^{0}}\) * \(k_{1}\) * \(a^{2^{1}}\) * \(k_{2}\) * \(a^{2^{2}}\) *...* \(k_{2^{\log_{2}b}}\) * \(a^{2^{\log_{2}b}}\)(其中\(k_{n}\)均为0或1),也就是将b分解为 \(k_{0}\) * \(2^{0}\) + \(k_{1}\) * \(2^{1}\) + \(k_{2}\) * \(2^{2}\) +...+ \(k_{2^{\log_{2}b}}\) * \(2^{\log_{2}b}\) 。

这种分解方式的计算十分简单,只需要计算b的二进制表示,即可求出\(k_{n}\)(n=0,1,2,...,\(2^{\log_{2}b}\))的值。

同时,分解出的因数进行模p运算也非常简单:因为分解出的每一项\(a^{2^{n}}\)都是上一项\(a^{2^{(n-1)}}\)的两倍。所以:计算要 \(a^{2^{n}}\) % p ,只需要计算\( ( a^{2^{(n-1)}} \)% p ) * \( ( a^{2^{(n-1)}}\) % p ) % p 而无需计算出\(a^{2^{n}}\)本身的值。由第一项开始进行递推,即可在一次循环内完成整个运算过程!

在实际的代码中,我们可以发现:“计算b的二进制表示”,和“将分解出的因数进行模p运算”,可以同时进行,进一步简化流程。

c++的代码如下:

/*
输入:a,b,p
输出:a^b%p
*/
#include<iostream>
using namespace std;
long long int qmi(long long int a, long long int b, long long int p) {
    long long res = 1;
    while (b) {
        //如果b的二进制的第0位是1,就表示kn为1,更新当前余数
        if (b & 1) res = res * a % p;
        b /= 2;
        a = a * a % p;
    }
    return res;
}
int main() {
    long long int a, b, p;
    cin >> a >> b >> p;
    cout << qmi(a, b, p) << endl;
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值