快速幂及快速幂取余

快速幂及快速幂取余


快速幂
当遇到求ana^nan这种问题时,可以将指数n拆开于是变成(a2)n/2(a^2)^{n/2}(a2)n/2。然后重复将n除2,底数平方,直到指数为0为止就是结果。于是解决这题的时间复杂度从O(n)O(n)O(n)(普通循环相乘a的做法)到了O(logn)O(logn)O(logn)
这就是快速幂算法,本身还是挺简单的,主要思想就是让底数变大,指数不断缩小。
唯一要考虑的就是当n是奇数时需要将式子变成a∗an−1a*a^{n-1}aan1,然后再n除二,底数平方(因为小数次方计算机不好计算),代码如下。

int f(int a,int n)
{
	int ans=1;
	while(n){
		if(n%2){			//一个技巧是把n%2改成n&1也能达到一样的效果,而位运算的效率要高于求余
			n-=1;			//n是奇数时
			ans*=a;			//最后n=1的时候会从这里结束
		}else{
			n/=2;			//n是偶数时		也有一个技巧是n/=2改成n>>=1
			a*=a;
		}
	}
	return ans;
}

可是滑稽的是因为指数爆炸,a=2 n等于64时的结果便超过了长整形的数据范围,所以这个算法并没有卵用,所以这个模板只适用于大数模拟的快速幂,或者将这个算法与快速幂求余一起讨论。

快速幂取余
当遇到求an%ba^n\%ban%b这种问题时,可以利用求余的基本运算法则,基本运算法则如下:
  1.(a+b)%c=(a%c+b%c)%c1.(a+b)\%c=(a\%c+b\%c)\%c1.(a+b)%c=(a%c+b%c)%c
  2.(a−b)%c=(a%c−b%c)%c2.(a-b)\%c=(a\%c-b\%c)\%c2.(ab)%c=(a%cb%c)%c
  3.(a∗b)%c=(a%c∗b%c)%c3.(a*b)\%c=(a\%c*b\%c)\%c3.(ab)%c=(a%cb%c)%c
类似于普通四则运算,不过没有除法。
第三点可以容易证明ab%c=(a%c)b%ca^b\%c=(a\%c)^b\%cab%c=(a%c)b%c

利用这点和快速幂算法就可把此问题中的指数除二得到((a2)n/2)%b=((a2%b)n/2)%b((a^2)^{n/2})\%b=((a^2\%b)^{n/2})\%b((a2)n/2)%b=((a2%b)n/2)%b  (n为偶数),接下来就是和快速幂的做法一样了,将n不断缩小直至为1为止,同样也要考虑奇数,所以代码只需稍作修改如下。

int f(int a,int n,int b)
{
	int ans=1;
	a%=b;					//防止a*a溢出
	while(n){
		if(n&1){
			n-=1;			
			ans=(ans*a)%b;	//只需要加个求余符号即可
		}else{
			n>>=1;			
			a=(a*a)%b;
		}
	}
	return ans%b;			//多求余一次防止n等于0时出现意外错误
}

以上便是快速幂取模,复杂度同样是O(logn)O(logn)O(logn)。要注意的是b2b^2b2不能超出数据范围,不然会溢出。
快速幂取模可以常见使用于求某一个ana^nan的后几位数,比如an%1000a^n\%1000an%1000就是得到后三位数的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值