快速幂

前言

本蒟蒻最近刚好刷完搜索部分,该刷分治算法了。第一题就是快速幂的模板题,今天我就顺着这道题讲讲刚学来的快速幂算法(话说快速幂好像没用到分治啊)吧。(写得不好勿喷)

原理

如果你要用电脑计算\(a^b\),怎样快速求出解呢?
最容易想到的就是暴力运算\(b\)次,思路是简单,可惜速度不快。而相比较下,快速幂的速度就很快了。(看名字)
比如你想计算\(3^{13}\)\(13\)在二进制下\((1101)_2\),所以\(13\)就可以表示为\(2^0+2^2+2^3\),根据\(a^{x+y}=a^x\times{a^y}\)可以推导出:
\(3^{13}=3^{2^0+2^2+2^3}=3^{2^0}\times{3^{2^2}}\times{3^{2^3}}\)
也就是\(a^b\)变为多个\(a^{2^n}\)相乘的形式(\(n\)为二进制下\(1\)所在的位)

实现

讲完了原理,实现也就不难了。
首先我们要检查二进制每一位是否为\(1\),将\(a\)自乘来表示\(a^{2^n}\),即每检查一位就自乘一次,如果该位为\(1\)就乘到答案(\(ans\))上
介绍一下c++下的位运算:

/*
>> 右移运算
比如1101001‬右移一位得到110100(最后一位没了)
& 与
这里运用&1,若最后一位为1就返回1,最后一位为0就返回0,起到检查位的作用
*/

所以我们不断用>>右移直到只剩下0,并用&来检查每一位是否为\(1\)
代码实现:

long long quickpow(long long a,long long b)
{
    long long ans=1;  //用来储存答案
    while(b>0)  //循环,检查每一位
    {
        if(b&1) ans*=a;  //这一位为1,乘上a^2^n
        a*=a;  //自乘,表示a^2^n
	b>>=1;  //右移,下一位
    }
    return ans;  //返回答案
}

例题讲解

洛谷P1226【模板】快速幂||取余运算
输入\(b,p,k\),输出\(b^p\bmod{k}\)
这似乎可以直接输出\(ans\bmod{k}\),但这样做会爆long long。
根据性质\((x\times{y})\bmod{z}=[(x\bmod{z})\times{(y\bmod{z})}]\bmod{z}\),所以我们应该对每步运算取模(等同于对结果取模)。

long long quickpow(long long a,long long b,int m)  //增加参数m,计算a^b mod m
{
    long long ans=1;
    while(b>0)
    {
        if(b&1)
        {
             ans*=a;
             ans%=m;  //取模
        }
        a*=a;
        a%=m;  //取模
	b>>=1;
    }
    return ans%m;  //也要进行取模
}

注意:最终结果要再进行一次取模,例如计算\(2^0\bmod{1}\),如果不取模就会返回1(正确答案是0)。

学习参考:https://www.luogu.com.cn/blog/cicos/quickpow#

posted @ 2020-02-16 20:16  stdout  阅读(130)  评论(0)    收藏  举报