快速幂(分治思想)

200 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

快速幂是分治思想的一个典型的应用。 最大的特点是能够快速计算出a的b次方是多少。原理如下: 例如:计算 2 的 5 次方和 2 的 6 次方

传统的计算方式是使用循环,每次都去乘以底数本身,这样虽然很直观,但是当次数多起来的时候,需要通过很多次循环才能达成目标,例如2的5次和6次,需要分别进行5次和6次循环,而如果使用快速幂的话,循环次数则降低到3次,若是2的16次方,则可将传统的16次循环降低到5次循环 在这里插入图片描述

首先从 1 开始(因为非0的数乘以1之后还是本身),拿计算 2 的 5 次方来说,通过不断地乘以底数可以快速的让指数翻倍,进行成倍的增长。拿上面的例子来说,从 1 开始时,先暂时设一个 变量 ans 存放最终答案。一开始 ans 为 1 ,然后让 ans = 2 * 2;此时 ans 为 4 也就是 2 的 2次方此时,然后重复此操作,但是遇到指数为奇数时应该多乘以一个底数,同时指数也应该除以 2 ,取整,忽略小数部分

至于原因则是:同底数幂相乘,底数不变,指数相加,而一个数平方之后,相当于指数乘以2

为什么指数为奇数的时候要多乘以一个数呢? 指数在除以二取整之后,会忽略小数部分,而正常情况下这个是有一次方的

在模拟一次过程后会发现随着指数的下降,底数的乘积也在不断的增大,所以它们相互抵消掉了。用我的不标准语言表示就是 a 的 b 次方等于 a 的 2/b次方 乘以a 的 2/b次方(中间的除号是分数线),a 的 c 次方 = a * a,a 的 b 次方等于 a 的 c 次方,b 减小了,c 增大了。 计算 2 的 6 次方的时候也是同样的原理。

下面是代码

#include <iostream>

using namespace std;

long long k(long long a,long long b)
{
	long long base = a; //保存底数 
	a = 1;
	while (b > 0)
	{
		if (b & 1 != 0) //判断指数b是否为奇数
		{
			a = base * a;
		} 
		base = base * base;//底数相乘
		b = b >> 1; //右移,相当于除以2 
	}
	return a;
}

int main()
{
	ios::sync_with_stdio(false);
	long long n,d;
	long long ans;
	cin >> n >> d;
	ans = k(n,d);
	cout << ans << endl;
	return 0;
}