题目:求a∗bmod  pa*b\mod pa∗bmodp的值,其中 111≤aaa,bbb,ppp≤101810^{18}1018
方法一
快速幂变形,将b用二进制表示,即快速幂变形,将b用二进制表示,即快速幂变形,将b用二进制表示,即b=ck−12k−1b=c_{k-1}2^{k-1}b=ck−12k−1+ck−12k−2c_{k-1}2^{k-2}ck−12k−2 +.........+c020c_{0}2^{0}c020
则a∗b=ck−12k−1∗aa*b=c_{k-1}2^{k-1}*aa∗b=ck−12k−1∗a+ck−12k−2∗ac_{k-1}2^{k-2}*ack−12k−2∗a +.........+c020∗ac_{0}2^{0}*ac020∗a
∵a∗2k=(a∗2k−1)∗2∵a*2^{k}=(a*2^{k-1})*2∵a∗2k=(a∗2k−1)∗2;
∴只要观察到ck=1,则ans=ans∗amod  p∴只要观察到c_{k}=1,则ans=ans*a\mod p∴只要观察到ck=1,则ans=ans∗amodp
每一次位移,都要a=a∗amod  p每一次位移,都要a=a*a\mod p每一次位移,都要a=a∗amodp
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
ll mul(ll a,ll b,ll p)
{
a%=p;ll ans=0;
while(b)
{
if(b&1)ans=(ans+a)%p;
b>>=1;a=(a<<1)%p;
}
return ans;
}
int main()
{
ll a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
printf("%lld\n",mul(a,b,c));
return 0;
}
方法二
用longlong自然溢出
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll mul(ll a,ll b,ll p)
{
a%=p,b%=p;
ll c=(long double)a*b/p;//向下取整
ll ans=(a*b-c*p+p)%p;
return ans;
}
int main()
{
ll a,b,p;scanf("%lld%lld%lld",&a,&b,&p);
printf("%lld\n",mul(a,b,p));
return 0;
}