题目链接:https://www.luogu.com.cn/problem/P1226
对于这个问题,当然可以将p个b相乘,但是p的上限是231,而算法的时间复杂度为O§,承受不了这么大的规模。
快速幂
想弄清本题算法,需要先了解取模(求余)运算的一些性质,比如:
递归实现
递归的思想就是利用二分法。它基于如下事实:
(1)如果p是奇数,那么有bp=b*bp-1
(2)如果p是偶数,那么有bp=bp/2*bp/2
且临界值b0=1.
注意:不能直接写成return binaryPow(b,p/2,k)*binaryPow(b,p/2,k)%k;
,这样的话时间复杂度为O(2logp)=O( p )。
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
LL binaryPow(LL b,LL p,LL k){
if(p==0) return 1;
if(p&1==1) return b*binaryPow(b,p-1,k)%k;
LL mul=binaryPow(b,p/2,k);
return mul*mul%k;
//return binaryPow(b,p/2,k)*binaryPow(b,p/2,k)%k; 这么写可不行
}
int main() {
LL b,p,k;cin>>b>>p>>k;
printf("%lld^%lld mod %lld=%lld",b,p,k,binaryPow(b,p,k)%k); //由于p==0时函数没有对其进行取余操作,所以在这里加一句取余比较保险
return 0;
}
非递归算法
如果把p写成二进制,那么b就可以写成若干二次幂之和,例如13的二进制是1101,于是13=23+22+20=8+4+1,所以b13=a8*a4*a1.
类似的,对于任意ab,它可以表示为a2k,…,a4,a2,a1中若干项的成绩。其中,若b的二进制i号位位1,则a2i就被选中。
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
int main() {
LL b,p,k;cin>>b>>p>>k;
printf("%lld^%lld mod %lld=",b,p,k);
LL ans=1;
while(p>0){
if(p&1==1){
ans=ans*b%k;
}
b=b*b%k;
p>>=1;
}
printf("%lld",ans%k);
return 0;
}