快速幂
Posted cjl-world
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速幂相关的知识,希望对你有一定的参考价值。
快速幂顾名思义,就是快速算某个数的多少次幂。
其时间复杂度为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;
}
以上是关于快速幂的主要内容,如果未能解决你的问题,请参考以下文章