原题链接:64位整数乘法
解题思路
方法一
类似快速幂的思想,把整数 b 用二进制表示,即b=c(k-1)pow(2,k-1)+c(k-2)pow(2,k-2)+......+c(0)pow(2,0)
,那么a*b=c(k-1)*a*pow(2,k-1)+c(k-2)*a*pow(2,k-2)+......+c(0)*a*pow(2,0)
。
因为a*pow(2,i)=(a*pow(2,i-1))*2
,若已求出a*pow(w,i-1) mod p
,则计算(a*pow(2,i-1))*2 mod p
时,运算过程中每一步的结果都不超过2*pow(10,18)
,仍然在64位整数 longlong 的表示范围内,所以很容易通过 k 次递推求出每个乘积项。当 c(i)=1 时,把乘积项累加到答案中即可。
样例代码
#include<bits/stdc++.h>
using namespace std;
unsigned long long mul(unsigned long long a,unsigned long long b,unsigned long long p)
{
a%=p,b%=p;
unsigned long long c=(long double)a*b/p;
unsigned long long x=a*b,y=c*p;
long long ans=(long long)(x%p)-(long long)(y%p);
if(ans<0)
ans+=p;
return ans;
}
int main()
{
long long a,b,p;
cin>>a>>b>>p;
cout<<mul(a,b,p);
return 0;
}
方法二
如果直接计算a乘b这会超过 long long 的最大范围,所以采用类似于快速幂的思想
把 b写成二进制形式,然后如果某位上为1就加上它a*(2^n)次方(n与这位的位置有关)
并且每次计算后取模就可以了
例:计算 3*7
7的二进制 111
3*(2^0)=3
3*(2^1)=6
3*(2^2)=12
观察可发现每次的可由前一次*2推出(记得取模)
样例代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
ll a , b , p , res;
cin >> a >> b >> p;
res = 0;
while (b)
{
if (b & 1)
res = (res + a) % p;
b >>= 1;
a = 2 * a % p;
}
cout << res;
return 0;
}