求 a 乘 b 对 p 取模的值,其中 1≤a,b,p≤10^18
跟快速幂的实质一样
我们用快速幂的思想,将b用二进制表示
b=ck-12k-1+ck-22k-2+…+c020
那么:
a×b=a×(ck-12k-1+ck-22k-2+…+c020)=a×ck-1×2k-1+a×ck-2×2k-2+…+a×c0×20
又
a×2i=(a×2i-1)×2
于是我们可以递推地计算出a×2i并且每次计算把答案加入ans中与快速幂不同的是ans的初始化并不是赋值为1而是清0.时间复杂度为O(log2 b).
在此基础上我们考虑如果a,b是负数那怎么办呢?为了解决这个问题我们考虑打一个标记w,我们将w的初始值赋值为1,如果a,b的值是负数的话就把w值取w=-w(a,b均做一次判断),我们把返回ans×w即可.
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include <climits>
#include<queue>
#include<vector>
#include <string.h>
#include <math.h>
#include<map>
#include<string.h>
#define ll long long
using namespace std;
ll mul(ll a,ll b,ll p){
ll ans=0;
int w=1;
if(b<0){
w=-w;
b=-b;
}
if(a<0){
w=-w;
a=-a;
}
if(a<b){
ll t=a;
a=b;
b=t;
}
while(b){
if(b&1){
ans=(ans+a)%p;
}
a=(a*2)%p;
b>>=1;
}
return w*ans;
}
int main()
{
// freopen("in.txt","r",stdin);
ll p,a,b;
scanf("%lld %lld %lld",&a,&b,&p);
printf("%lld\n",mul(a,b,p));
return 0;
}
这只是一个简化一定程度的算法,具体可查看
https://www.cnblogs.com/FJ-LinHua/p/9152631.html