快速幂?再加个位运算吧
快速幂概念
其实就是算a^n的操作,但是有些时候,如果用暴力法直接算,复杂度是O(n),有时候是会造成超时的。
快速幂的方法相信很多人早已经掌握了,先算a^2,再算a^2的平方,一直算到n次幂。这其实就是典型的分治思想,复杂度为O(logn)。直接上个代码:
int fastPow(int a,int n){
if(n==1)return a;
int temp=fastPow(a,n/2);
if(n%2==1)//奇数个a
return temp*temp*a;
else//偶数个a
return temp*temp;
}
上面的代码层数只有O(logn),不需要担心溢出的问题。
但是,还可以有更好的方法,放弃递归,直接利用循环递推,再套上个位运算,是不是感觉还能加快效率?
例如a^11,先把其分解成a^8、a^2、a^1的乘积。
如何求a^8、a^2、a^1的值,需要分别计算吗?并不需要,很好观察出,产生的a^i都是倍乘的关系,这个功能用“base*=base”实现。
有一个需要处理的问题:如何跳过那些不需要的?例如a^11,因为11=8+2+1,需要跳过4。这里做个判断即可,11的二进制为1101,这其中的0就是需要跳过的。这个判断,利用二进制的位运算很容易实现:
(1)n&1,取n的最后一位,并且判断这意味是否需要跳过。
(2)n>>1,把n右移一位,目的是把刚处理过的n的最后一位去掉。
其实,n&1可以直接理解为判断奇数的操作,而n>>1,可直接理解为n/2的操作,这实质上也可以算是分治的思想,不过利用位运算的效率明显会更高,因此完全可以用二进制思想来理解!
代码如下:
int fastPow(int a,int n){
int base=a;
int res=1;
while(n){
if(n&1)res*=base;
base*=base;
n>>=1;
}
return res;
}
快速幂取模
由于幂运算的结果非常大,常常会超过变量类型的最大值,甚至超过内存所能存放的最大数,所以设计快速幂的题目,通常都要做取模操作,缩小结果。
根据模运算的性质,在快速幂中做取模操作,对a^n取模,和先对a取模再做幂运算的结果是一样的,即:
a^n mod m=(a mod m)^n mod m
代码如下:
const int mod=1e9+7;//根据题意选择
int fastPow(int a,int n){
int base=a;
int res=1;
while(n){
if(n&1)res=(res*base)%mod;
base=(base*base)%mod;
n>>=1;
}
}
矩阵快速幂
给定一个m*m的矩阵A,求其n次幂,这也是常见的计算。同样也有矩阵的快速幂运算,把矩阵当成变量来对待就好了。
首先需要定义矩阵的结构体,并且定义矩阵相乘的操作。注意矩阵相乘也需要取模。
代码如下:
const int MAXN=2;
const int MOD=1e4;
struct Matrix{
int m[MAXN][MAXN];
Matrix(){
memset(m,0,sizeof(m));
}
};
Matrix Multi(Matrix a,Matrix b){
Matrix res;
for(int i=0;i<MAXN;++i)
for(int j=0;j<MAXN;++j)
for(int k=0;k<MAXN;++k)
res.m[i][j]=(res.m[i][j]+a.m[i][k]*b.m[k][j])%MOD;
return res;
}
下面就是矩阵快速幂的代码,和前面的快速幂代码很相似:
Matrix fastm(Matrix a,int n){
Matrix res;
for(int i=0;i<MAXN;++i)
//初始化为单位矩阵,相当于前面的res=1
res.m[i][i]=1;
while(n){
if(n&1)res=Multi(res,a);
a=Multi(a,a);
n>>=1;
}
return res;
}
更多推荐


所有评论(0)