題目鏈接: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;
}