快速幂算法计算a^b%p的值

1,283 阅读3分钟

题目描述

image.png 题目链接www.acwing.com/problem/con…


思路解析

由题可知,这道题虽然看起来可以用暴力方法求解,但暴力解法时间复杂度过大(O(n)),题目要求的时间限制为1秒,因此我们可以使用快速幂的思想来解决这道题,即利用快速计算[底数]的n次幂的思想简化计算过程。 快速幂算法的基本步骤如下:

将指数转换为二进制形式。
从右到左遍历二进制数的每一位。
如果某位为1,则将底数乘以自身的平方。
如果某位为0,则仅将底数平方。
每次迭代后,指数右移一位(相当于除以2)。
重复步骤25,直到指数变为0

快速幂代码模板:

int qmi(int a, int b, int p)
{
	// 计算a^b%p的值
	int res = 1 % p;
	while (b)// 从右到左遍历二进制后的指数的每一位
	{
         // 如果某位为1,则将底数乘以自身的平方。 
         // 如果某位为0,则仅将底数平方。
		if (b & 1)res = res * a % p;
		a = a * a % p;// 将底数平方
		b >>= 1;// 指数右移1位
	}
	return res;// 返回最后的结果
}

例如:求3^31的值:

求3的31次方,如果按照暴力方法就是直接循环,但当数据大了以后肯定会超时,因此我们可以先将31转换为二进制,31=011111=2^4+2^3+2^2+2^1+2^0

我们令:

a1=3^1=3^(2^0)=3

a2=3^2=3^(2^1)=(3^1)*(3^1)=a1*a1

a3=3^4=3^(2^2)=(3^2)*(3^2)=a2*a2

a4=3^8=3^(2^3)=(3^4)*(3^4)=a3*a3

a5=3^16=3^(2^4)=(3^8)*(3^8)=a4*a4

31=1+2+4+8+16

3^31
=a1*a2*a3*a4*a5
=(3^1)*(3^2)*(3^4)*(3^8)*(3^16)
=3^(1+2+4+8+16)=3^31

因此,通过将指数用二进制来表示,我们就可以把时间复杂度为O(n)的算法,转换成了时间复杂度为O(logn)的算法,避免了因数据过大而导致运算时间过久的情况。因此要计算a^b%p的值,可以由如下方法实现:


代码实现

// 求a的b次方对p取模的值
#include<iostream>
using namespace std;
int main()
{
	int a, b, p;
	// 输入a,b,p的值
	cin >> a >> b >> p;
	// 如果定义res=1
	// 当a^b的值为1,p也为1时,正确答案应该为0,但res为1,所以定义res=1%p
	int res = 1 % p;
	// 当b为0时,
	// 不管a为什么值,a^b都为1,且会直接跳出循环,
	// 最后的结果均为 1%p,也就是刚开始定义的res的值
	while (b)
	{
		// 从b的二进制位的第一位开始,如果为1,则乘a
		// *1ll相当于将res强制类型转换为长整型
		if (b & 1)res = res * 1ll * a % p;
		// 此处%p是为了防止溢出
		// 因为一个数,不管模多少次p,结果始终和模一次p的值一样
		a = a * 1ll * a % p;// 将a的值进行平方
		// 将b的二进制位向右移动一位,当b=0则跳出循环
		b >>= 1;
	}

	// 输出结果
	cout << res << endl;

	return 0;
}

运行结果:

image.png


这道题的介绍到这里就结束了,如果你觉得本篇文章对你多少有些帮助,可以点个赞或者收藏一波支持一下哦,欢迎各位大佬批评指正,咱们下一道题再见!