在我们进行乘法运算的时候,很多情况下会爆\(long\:long\),所以我们急需寻找一种高效的方法来完成乘法运算并且不会爆\(long\:long\)。
移位快速乘,思想是把\(a\times b\%p\)中的\(b\),对其进行二进制拆分,把\(b\)拆成二进制形式。\(a\times b=C_{k-1}\times a\times2^{k-1}+C_{k-2}\times a\times2^{k-2}+\dots+C_{0}\times a\times2^{0}\),其中\(c\)表示二进制数位。
例如:\(21\times13\),将\(13\)转化成二进制\(1101\),则就是\(20\times2^0+20\times2^2+20\times2^3\)。(类似于快速幂)
typedef long long ll;
ll qmul(ll n, ll b, ll mod){
ll res = 0;
while(n){
if(n & 1) res = (res + b) % mod;
b = (b + b) % mod;
n >>= 1;
}
return res % mod;
}
利用的是很简单的一个浮点数类型。\(long\:double\)能保证数字的精确程度,然后再把这个数字进行计算。计算的方式很简单,\(a\times b\%p=a\times b-[\frac {a\times b}{p}]\times p\)。
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll qmul(ll x, ll y, ll mod){
ll temp = (ld)x / mod * y;
ll res = (ull)x * y - (ull)temp * mod;
return (res + mod) % mod;
}
看到这份代码有没有感到十分奇怪? 它直接用了乘法操作的啊? 这不直接爆了吗?但是它就是可以直接算出正确答案来。因为它很巧妙的运用了自动溢出这个操作,我们的代码中的\(temp\)就表示 \(?\frac{x\times y}{p}?\),所以我们要求的就变成了 \(x\times y??\frac{x\times y}{p}?\times p\) ,虽然这两个部分都是会溢出的,但(\(unsigned\))保证了它们溢出后的差值基本不变,所以即使它会溢出也不会影响最终结果的!
原文:https://www.cnblogs.com/hy2001/p/14828282.html