两个long long 的数相乘,模一个long long的数,怎么处理?
直接乘是肯定不行的,于是我们就要用到快速乘。
1.用long double
首先,我们知道a%b=a−⌊ab⌋×ba\%b=a-\lfloor\frac{a}{b}\rfloor\times ba%b=a−⌊ba⌋×b,所以x×y%p=x×y−⌊x×yp⌋×px\times y\%p=x\times y-\lfloor\frac{x\times y}{p}\rfloor\times px×y%p=x×y−⌊px×y⌋×p。
这里x,y,px,y,px,y,p都是long long的,显然x×yx\times yx×y可能会溢出,但是减去⌊x×yp⌋×p\lfloor\frac{x\times y}{p}\rfloor\times p⌊px×y⌋×p之后的结果肯定是小于ppp的。溢出后减回来结果是一样的。时间复杂度为O(1)O(1)O(1),适合用于卡常数的题目。
但是,因为long double有精度问题,所以如果数组过大的话返回值就会出问题。
code
long long ch(long long x,long long y,long long p){
return (x*y-(long long)((long double)x/p*y)*p+p)%p;
}
2.用二进制
与快速幂原理相似,原本x×yx\times yx×y为x+x+x+⋯+xx+x+x+\dots+xx+x+x+⋯+x连续加yyy个xxx。我们可以优化一下,对于yyy转为二进制中的第iii位,如果这一位为1,则ans+=x×2ians+=x\times 2^ians+=x×2i。所以只需枚举iii,具体与快速幂相似,时间复杂度为O(y)O(y)O(y)
code
long long ch(long long x,long long y,long long p){
long long re=0;
for(;y;y>>=1,x=(x+x)%p){
if(y&1) re=(re+x)%p;
}
return re;
}