啥是快速幂

啥是快速幂

这篇文章是为了帮一个同学学习ksm写的

百度百科给的定义:

顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。

这是一种能够快速的计算出(a^b)的值的算法

如果暴力计算(a^b)需要把a乘自己b次,当b太大时,就会超时。

使用ksm就只用log₂b次,计算次数大大减小。

原理:

  1. 将a乘自己a*a=(a^2),再做同样的操作(a^2 *a^2=a^4);所以a自乘n次后就是(a^2n).

  2. (a^x *a^y=a^(x+y))

  3. 对于b,只要它是一个正整数,都可以把它拆成若干个2的不同次幂相加。

    如:11=(2^3+2^1+2^0)

    而11的二进制就是1011,也就是计算机里所储存的形式,更方便去对于b进行上述拆分。

过程:

定义两个数,temp和ans;temp即为要进行自乘的数初始值为上文所说的a;ans初值为1,即为答案,(为什么是1呢,自己思考)。

while(b)//也就是当b大于0时

先判断b的最后一位是否为1

如果是就将ans*=temp;

if(b&1) ans=(1longlong*ans*temp);

关于 b & 1:
“&”就是“按位与”。
x & y 是二进制 x 和 y 的每一位分别进行“与运算”的结果。
与运算:即两者都为 1 时才会返回 1,否则返回 0。
那么 b & 1
b = 1011
1 = 0001
b&1 = 0001
因为 1的前面几位全部都是 0,
所以只有 b 二进制最后一位是 1 时,b & 1 才会返回 1。
挺巧妙的,并且很快。

之后将temp自乘,变成(a^2);

同时将b右移一位。

即:若b=11(10),二进制下b=1011(2);

右移一位就变成b=101(2);

temp=(1longlong*temp*temp);
b=>>1;

不断重复上述过程直到不满足while的条件b>0;

代码实现:

以luoguP1226为例

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long 
using namespace std;

ll b,p,k;

ll ksm(ll a,ll b,ll z)//快速幂函数
{
	//这里的temp可以直接用a来表示,不影响结果,可以自己想为什么
    ll ans=1;
	while(b)
	{
		if(b&1) ans=(1ll*ans*a)%z;
		a=(1ll*a*a)%z//自乘
		b>>=1;//右移
	}
	return ans;
}

int main()
{
	scanf("%lld%lld%lld",&b,&p,&k);
	printf("%lld^%lld mod %lld=%lld",b,p,k,ksm(b,p,k)%k);
	return 0;
}
原文地址:https://www.cnblogs.com/plzplz/p/12081233.html