快速冪
阿新 • • 發佈:2020-06-27
快速冪顧名思義,就是快速算某個數的多少次冪。
其時間複雜度為O(log₂N),與樸素的O(N)相比效率有了極大的提高。
核心思想就是
如果\(k\)是偶數 那麼 \(x^ k =(x^{2})^{\tfrac{k}{2}}\)
如果\(k\)是奇數 那麼 \(x ^ k = x * x ^{ ( k - 1 ) }\)
遞迴實現即可
#define LL long long
LL quickpow(LL x,LL k,LL mod) { if(k==0) return 1; if(k&1) return x*quickpow(x,k-1,mod)%mod; else return quickpow(x*x%mod,k>>1,mod)%mod; }
另一種想法就是
如果\(k\)是偶數 \(x^ k =(x^{\tfrac{k}{2}})^{2}\)
如果\(k\)是奇數 \(x ^ k = x * ( x ^{ \tfrac{k}{2}} ) ^ 2\)
LL quickpow(LL x,LL k,LL mod)
{
if(k==0) return 1;
LL t=q_pow(x,k>>1,mod)%mod;
if(k&1) return ((t*t%mod)*x)%mod;
return t*t%mod;
}
另外,如果想寫(\(k\)&\(1\))\(==\) 0 的話,
注意& 按位與的優先順序比 等號 低 ,要加括號
二進位制拆分
這是最重要的一種計算方法。
\((13)_{10}=(1101)_{2}\)
\(a^{13}=a^{8}*a^{4}*a^{1}\)
也就是說,我們通過計算 \(a^{2^{i}},i \in [0,1+log_{2}k]\)
再把這些解乘起來(如果k的二進位制第i位是0,就不用乘),就可以得到 \(a^{k}\)
詳情見:https://www.luogu.com.cn/blog/cicos/quickpow
真的是很好的一篇題解。
Code:
LL quickpow(LL x,LL k,LL mod) { LL res=1; while(k) { if(k&1) res=res*x%mod; x=x*x%mod; k>>=1; } return res%mod; //注意要返回res%mod,hank 1^0(mod 1) }
但是如果把每一位預處理出來,存在 \(g[]\) 裡( \(g[i]=a^{2^{i}}\) ), 就有
LL quickpow(LL x,LL k,LL mod)
{
LL res=1;
for(int i=0;i<=LOGK&&k;i++) {
if(k&1) res=res*g[i]%MOD; //二進位制此位為1
k>>=1;
}
return res%MOD;
}
其實寫法一較為方便,
但是也有用到寫法二的題(單次*複雜度高,底數相同,只要部分解)
洛谷模板題
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL b,p,k;
LL power(LL n,LL m,LL k)
{
LL res=1LL;
while(m) {
if(m&1) res=(res*n)%k;
n=n*n%k; m>>=1LL;
}
return res%k;
}
int main()
{
scanf("%lld%lld%lld",&b,&p,&k);
printf("%lld^%lld mod %lld=%lld\n",b,p,k,power(b,p,k));
return 0;
}