快速幂
原题链接:快速幂
ac代码:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL qmi(int a,int b,int p)
{
LL res=1%p;
while(b)//这里本应该分两次进行,不过只有一次询问
{
if(b&1)res=res*a%p;//不断得出结果并直接相乘
a=a*(LL)a%p;//为了积累下一次幂
b>>=1;
}
return res;
}
int main(){
int n;cin>>n;
while(n--)
{
int a,b,p;
cin>>a>>b>>p;
printf("%d\n",qmi(a,b,p));
}
return 0;
}
这里对方法主题进行逐句分析:
LL res=1%p;
这里为什么要%p呢?
我们可以考虑这个情况:当p=1,b=0时,无论a取何值,循环都不会进入,那么如果这里不对q求余,那么res=1,可是正确答案为res=0;
下面对主要部分做解释:
while(b)//这里本应该分两次进行,不过只有一次询问
{
if(b&1)res=res*a%p;//不断得出结果并直接相乘
a=a*(LL)a%p;//为了积累下一次幂
b>>=1;
}
那什么是快速幂呢?这里给出一个问题:求
(
a
b
)
m
o
d
p
;
(a^b)mod p;
(ab)modp;
如果这里b的数据范围是1e9,计算1e9次,那么会爆tle,所以我们引入了快速幂,快速幂是基于二进制对于算式的优化:
通过优化,我们将o(n)的时间复杂度优化为log(n),
那么我们对这个代码就基本理解了:
if(b&1)res=res*a%p;//不断得出结果并直接相乘
a=a**(LL)a%p;//为了积累下一次幂
b>>=1;
如果b的二进制最小位为1,那么进入进行计算,比如8是100,那么第一位不计算,a在下一句进行累加取余,b去掉最小位,第二位不计算,a继续累乘取余,在第三位进行乘。每次的分步取余是为了防止结果溢出,防止结果错误。
同时注意!res和a都要开long long不然数据过大会溢出