快速幂(a^b%mod)

发布时间 2023-10-13 17:00:31作者: Enid_Lin

一、快速幂的作用

  • 在求ab时,使用for循环一点一点求,就是幂运算的O(b)算法。
  • 而使用快速幂求解,就是幂运算的O(logb)算法。

二、思路

  • 引理:积的取余等于取余的积的取余。
  • 思路:在以上引理的基础之上再对指数型数据进行拆分和合并从而得到快速幂算法。

三、快速幂具体分析

​ 对于当a和b较小是直接用int或者long存是没有问题的,但是当a和b大到一定程度时,这就不是暴力存就可以解决的问题了。

​ 说到底就是“大”的问题,所以我们要想办法不断地减小a和b的规模,所谓逐个击破。

​ 引理,我们知道了可以把指数拆开:

//a是底数,b是指数,mode是取模数,sum是记录取模的结果
int sum = 1;
a = a % mode; 
for(int i = 1; i <= b; i++)
{
    sum = sum * a;
}
sum = sum % mode;

以上a的规模只被降低一次,我们可以进一步地降低a的规模,将其中的sum = sum * a改成sum = (sum * a)%mode)

​ 接着是降低b的规模,我们知道求解716可以将底数7两两合并,变成498,这样就把指数b的规模降低了,再利用上面的算法降低a的规模,多循环几次,就形成了快速幂算法。

​ 但如果b为奇数,就无法两两合并,于是就在偶数的算法基础上,每次都先取出一个数,使其变为偶数。最终得出快速幂算法。

四、快速幂的代码

​ 根据以上的分析,得出算法代码如下:

  1. 根据以2为模取余来判断奇偶性
long long Mode(long long a, long long b, long long mode)
{
    long long sum = 1;
    a = a % mode;
 
    while (b > 0) {
        if (b % 2 == 1)		//判断是否是奇数,是奇数的话将多出来的数事先乘如sum
            sum = (sum * a) % mode;
        b /= 2;
        a = (a * a) % mode;// 不断的两两合并再取模,减小a和b的规模
    }
    return sum;
}
  1. 根据&运算来判断奇偶性

    &的操作符:二进制位中,1 & 1 = 1,其余组合均为0。

    long long Mode(long long a, long long b, long long mode)
    {
        long long sum = 1;
        while (b) 
        {
            if (b & 1) 
            {
                sum = (sum * a) % mode;
                b--;
            }
            b /= 2;
            a = a * a % mode;
        }
        return sum;
    }
    

    也可以将b /= 2换成位运算b >>= 1

参考资料:https://blog.csdn.net/qq_24016309/article/details/88585522