快速幂算法

来源:互联网 发布:wacom mac 笔记软件 编辑:程序博客网 时间:2024/06/04 17:57

今天写题遇到几道快速幂和矩阵快速幂的题目,也为最近的比赛做准备,总结一下这个算法

对于整数求幂,通用的办法就是暴力,将其一个个乘起来也就是O(n)的复杂度

比如求n的m次方

#include<iostream>using namespace std;int main(){int n,m;cin>>n>>m;int ans=1;for(int i=1;i<=m;i++){ans*=n;}cout<<ans<<endl;return 0;}
但是如果题目对时间要求很严格且n又很大的时候呢
这个时候就要用到快速幂算法了

我们以3的11次方为例子。

将11用二进制表示是1011

然后3^11=3^(2^0)*3^(2^1)*3(2^3)(不过我也不知道为什么这么神奇......)

先上代码

#include<iostream>using namespace std;typedef long long ll;ll fun(ll a,ll b){ll ans=1;ll base=a;while(b){if(b&1) ans*=base;base*=base;b>>=1;}return ans;}int main(){ll n,m;while(cin>>n>>m){cout<<fun(n,m)<<endl;}}

从代码分析,我们先从二进制的操作来分析,&1就是判断一个数字的二进制的最后一位是不是1,>>就是将二进制数字右移一位。

1011 从右到左数就是0 1 2 3,结合3^11=3^(2^0)*3^(2^1)*3(2^3)我们就可以知道,当二进制位为0的时候我们是不会计算进去的,然后跟着上面的代码走一遍。

从1011的右边开始它的最后一位是1,所以我们乘上base,这时候的base是3,然后base与base相乘,这是为什么呢,因为我们要让2^0变成2^1(实际不是这样,但是为了方便理解,建议在纸上写一下....)。然后1011右移一位变成101,101的最后一位还是1,ans乘上base,这时的base等于9,所以ans等于27了,base再与base相乘,这时base等于81,101右移一位变成10,继续循环,10的最后一位不是1,ans不变,base与base相乘,base变为6561,10右移一位变成1,1的最后一位是1,所以ans乘上base,这时的ans等于27,base等于6561,相乘以后ans变为177417,base与base相乘,1右移一位变为0,循环结束。我们就得出了答案177147.

其实整个算法不是很难,最重要的是要自己在纸上写一下。

有时候由于long long的范围都不足以表示结果,所以有时候需要取模,以对1e9+7取模为例

#include<iostream>using namespace std;typedef long long ll;const int mod=1e9+7;ll fun(ll a,ll b){ll ans=1;ll base=a;while(b){if(b&1) ans=ans*base%mod;base=base*base%mod;b>>=1;}return ans;}int main(){ll n,m;while(cin>>n>>m){cout<<fun(n,m)<<endl;}}

部分思路来自:快速幂讲解

原创粉丝点击