64位整数乘法

22 阅读2分钟

题目描述

image.png 题目链接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)。
重复步骤25,直到b变为0

例如:求3*31的值: 则a=3b=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;
}

运行结果: image.png


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