题目描述
求 a 乘 b 对 p 取模的值,其中 1≤a,b,p≤10^18
链接:https://ac.nowcoder.com/acm/contest/996/C
来源:牛客网
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,p,ans=0,n=1;cin>>a>>b>>p;a%=p;b%=p;
while(b){
if(b&1){
ans=(ans+a)%p;
}
a=a*2%p;
b>>=1;
}
cout<<ans;
return 0;
}
先对a,b取余。a%=p;b%=p;
将b看成二进制数。以b=13为例,二进制数为1101,则a*b变成了
a*(1+4+8)=1*a+4*a+8*a
所以我们可以把题目视作:
将b看成二进制数后,对b的每一位进行检查,如果第i位为1,就把其对应的2^i与a相乘,加入ans中。
循环i次,则a*(2^i)=a' *2, a'为前一个循环中的a。每次循环,a都乘一个2进来。
令我困惑的是,这样写代码就过不了:
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,p,ans=0;cin>>a>>b>>p;a%=p;b%=p;
long long n=1;
while(b){
if(b&1){
ans=(ans+(a*n)%p)%p;
}
n*=2;
b>>=1;
}
cout<<ans;
return 0;
}
下面是正确的代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,p,ans=0,n=1;cin>>a>>b>>p;a%=p;b%=p;
while(b){
if(b&1){
ans=(ans+a)%p;
}
a=a*2%p;
b>>=1;
}
cout<<ans;
return 0;
}
我将报错的写法和正确的写法做了个融合,也过不了。大家可以对比一下下面这个代码注释部分与打问号的部分有什么不同。自己试了很多样例,都是一样的,但就是不能过。
#include<bits/stdc++.h>
using namespace std;
int main(){
long long a,b,p,ans=0,n=1;cin>>a>>b>>p;a%=p;b%=p;
while(b){
if(b&1){
ans=(ans+a)%p;
}
//a=a*2%p;
n*=2;//?
a=a*n;//?
a=a%p;//?
b>>=1;
}
cout<<ans;
return 0;
}
不知道大家是否也有类似的困惑。