90. 64位整数乘法

原题链接: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;
}
posted @ 2020-11-29 22:24  hnkjdx_react  阅读(133)  评论(0编辑  收藏  举报