题目描述
题目链接:www.acwing.com/problem/con…
思路解析
由题可知,数据范围在1和10^18之间,而在C++中,长整型也最多只能表示一个19位的数,而10^18刚好就是19位,如果两个19位的数直接相乘,结果肯定是要溢出的,因为C++里面没有基本类型可以表示一个十进制位数为38位的数,所以要求
a*b%p
,我们可以用一种类似于快速幂的方法,将乘法转换为加法,来解决溢出问题,基本步骤如下:
将b转换为二进制形式。
从右到左遍历二进制数的每一位。
如果某位为1,则将a加上2a。
如果某位为0,则仅将a乘以2。
每次迭代后,b右移一位(相当于除以2)。
重复步骤2至5,直到b变为0
例如:求3*31
的值:
则a=3
,b=31
,我们将b转换为二进制,故b=011111=2^4+2^3+2^2+2^1+2^0=31
我们令:
a1=3*1=3*(2^0)=3
a2=3*2=3*(2^1)=3*(2^0+2^0)=a1+a1
a3=3*4=3*(2^2)=3*(2^1+2^1)=a2+a2
a4=3*8=3*(2^3)=3*(2^2+2^2)=a3+a3
a5=3*16=3*(2^4)=3*(2^3+2^3)=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
因此,通过将b用二进制来表示,将乘法转换为加法,进行分步运算,我们就可以避免因位数过大导致的溢出问题,因此要计算a*b%p
的值,可以由如下方法实现:
代码实现
#include<iostream>
using namespace std;
typedef unsigned long long ULL;// 无符号长整形
int main()
{
// 求 a乘 b对 p取模的值。
ULL a, b, p;
cin >> a >> b >> p;
ULL res = 0;// 最终要输出的结果
while (b)
{
// 从b的二进制位的第一位开始,如果为1,则加a
// 注:除第一次循环外,后续循环加上的a都是上一次循环中a的值的两倍
if (b & 1)res = (res + a) % p;
// 将a乘2
a = a * 2 % p;
// 将b的二进制位向右移动一位,当b=0则跳出循环
b >>= 1;
}
// 输出结果
cout << res << endl;
return 0;
}
运行结果:
这道题的介绍到这里就结束了,如果你觉得本篇文章对你多少有些帮助,可以点个赞或者收藏一波支持一下哦,欢迎各位大佬批评指正,咱们下一道题再见!