LuoguP1226 【模板】快速幂||取余运算

时间:2023-03-09 06:58:22
LuoguP1226 【模板】快速幂||取余运算

题目链接:https://www.luogu.org/problemnew/show/P1226

第一次学快速幂,将别人对快速幂原理的解释简要概括一下:

  计算a^b时,直接乘的话计算次数为b,而快速幂则只需要log2(b)次,很实用。

  快速幂有很多种解释,以下介绍两种:

  一.

    我们可以将b转换为二进制来看,比如计算2^11,因为(11)10=(1011)2,所以211=21*8+0*4+1*2+1*1=21×8×21×2×21×1

    具体计算可以参考代码:

int quickPower(int a, int b)//是求a的b次方
{
int ans = , base = a;//ans为答案,base为a^(2^n)
while(b > )//b是一个变化的二进制数,如果还没有用完
{
if(b & )//&是位运算,b&1表示b在二进制下最后一位是不是1,如果是:
ans *= base;//把ans乘上对应的a^(2^n) base *= base;//base自乘,由a^(2^n)变成a^(2^(n+1))
b >>= ;//位运算,b右移一位,如101变成10(把最右边的1移掉了),10010变成1001。现在b在二进制下最后一位是刚刚的倒数第二位。结合上面b & 1食用更佳
}
return ans;
}

  一般会将快速幂与取余运算结合在一起,例如本题。取余运算有一些很好的性质:

    (a+b) mod c = (a mod c + b mod c) mod c

    (a*b) mod c =((a mod c)*(b mod c)) mod c

  即在本题中求幂的过程中取余和求幂之后取余是一样的。另外,关于本题,有一个特殊情况,即k=1时,结果总为0,需要特判(最后一个测试点)。

  本题的AC代码如下:  

#include<cstdio>
using namespace std; long b,p,k,res=; void QuickPower(long bb,long pp,long kk){
long base=bb;
base%=kk;
while(pp){
if(pp&){
res*=base;
res%=kk;
}
base*=base;
base%=kk;
pp>>=;
}
} int main(){
scanf("%ld%ld%ld",&b,&p,&k);
if(k!=){
QuickPower(b,p,k);
printf("%ld^%ld mod %ld=%ld\n",b,p,k,res);
}
else
printf("%ld^%ld mod %ld=0\n",b,p,k);
return ;
}

  二.关于快速幂的另一种理解方式:

  对于a^b,若b为偶数,递归计算(a2)b/2;若b为奇数,则递归计算a*(a2)(b-1)/2