快速幂

快速幂顾名思义,就是快速算某个数的多少次幂。
其时间复杂度为O(log₂N),与朴素的O(N)相比效率有了极大的提高。


核心思想就是
如果(k)是偶数 那么 (x^ k =(x^{2})^{ frac{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^{ frac{k}{2}})^{2})
如果(k)是奇数 (x ^ k = x * ( x ^{ frac{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
",b,p,k,power(b,p,k));
	return 0;
}
原文地址:https://www.cnblogs.com/cjl-world/p/13190482.html