快速幂?再加个位运算吧

快速幂概念
其实就是算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;
}
  • 12
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布布要成为最负责的男人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值