1. 程式人生 > 實用技巧 >快速冪

快速冪

快速冪顧名思義,就是快速算某個數的多少次冪。
其時間複雜度為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;
}