一、例题
求 a 乘 b 对 p 取模的值。
输入格式
第一行输入整数a,第二行输入整数b,第三行输入整数p。
输出格式
输出一个整数,表示a*b mod p的值。
数据范围
1≤a,b,p≤1018
输入样例:
3
4
5
输出样例:
2
题目来源Acwing
二、思路分析
题目要让我们两个10e18的数相乘,必然会爆longlong,对于这种问题,我们的解法有两个,一个是高精度,另一个就是龟速乘。
三、算法介绍
先说一个很简单的思路,我们让结果加上 b 个 a,这样每次我们再加的同时来mod上p,那必然可以算出结果。但是b的范围会很大,10e18的数据量是肯定会超时的,为了解决这个问题,我们可以用龟速乘算法。
龟速乘就是来优化我们的加法,每次我们不是一次加一个a,而是每次加上 2 * a 个 a,比如:a ,2a,4a,8a… 2na.
我们在来看b,从b的二进制表示来说,b从二进制转化为十进制,就是和龟速乘类似的计算方式,比如b的二进制表示为(10110)则,b = 24 + 22 + 21, 因此我们结果就是 a * (24 + 22 + 21),而b的二进制位数最多只有64位,因此,时间复杂度只有为O(64),完美解决超时的情况。
代码模板
ll qadd(ll a,ll b,ll p)
{
ll res = 0;
while(b)
{
if(b & 1) res = (res + a) % p;
a = (a + a) % p;
b >>= 1;
}
return res;
}
四、完整代码
#include<iostream>
using namespace std;
typedef long long ll;
ll qadd(ll a,ll b,ll p)
{
ll res = 0;
while(b)
{
if(b & 1) res = (res + a) % p;
a = (a + a) % p;
b >>= 1;
}
return res;
}
int main()
{
ll a,b,p;
cin >> a >> b >> p;
cout<<qadd(a,b,p)<<endl;
return 0;
}
总结
龟速乘的模板和快速幂非常相似,因为龟速乘本质的思想和快速幂一样,快速幂就是乘法解决乘方,龟速乘则是用加分解决乘法。