long long binpow(long long a, long long b) {
if (b == 0) return 1;
long long res = binpow(a, b / 2);
if (b % 2)
return res * res * a;
else
return res * res;
}
long long binpow(long long a, long long b, long long m) {
a %= m;
long long res = 1;
while (b > 0) {
if (b & 1) res = res * a % m;
a = a * a % m;
b >>= 1;
}
return res;
}
注意:根据费马小定理,如果 m 是一个质数,我们可以计算 x^{n\bmod (m-1)} 来加速算法过程。
于是在算出 \left\lfloor\dfrac{ab}m\right\rfloor 后,两边的乘法和中间的减法部分都可以使用 unsigned long long 直接计算,现在我们只需要解决如何计算 \left\lfloor\dfrac {ab}m\right\rfloor。
我们考虑先使用 long double 算出 \dfrac ap 再乘上 b。
既然使用了 long double,就无疑会有进度误差。极端情况就是第一个有效数字在小数点后一位。因为 sizeof(long double)=16,即 long double 的进度是 64 位有效数字。所以 \dfrac ap 从第 65 位开始出错,误差范围为 \left(-2^{-64},2^{64}\right)。乘上 b 这个 64 位整数,误差范围为 (-0.5,0.5),再加上 0.5 误差范围为 (0,1),取整后误差范围位 \{0,1\}。于是乘上 -m 后,误差范围变成 \{0,-m\},我们需要判断这两种情况。
因为 m 在 long long 范围内,所以如果计算结果 r 在 [0,m) 时,直接返回 r,否则返回 r+m,当然你也可以直接返回 (r+m)\bmod m。
代码实现如下:
long long binmul(long long a, long long b, long long m) {
unsigned long long c =
(unsigned long long)a * b - (unsigned)((long double)a / m * b + 0.5L) * m;
if (c < m) return c;
return c + m;
}
buildLast update and/or translate time of this article,Check the history editFound smelly bugs? Translation outdated? Wanna contribute with us? Edit this Page on Github peopleContributor of this article OI-wiki translateTranslator of this article Visit the original article! copyrightThe article is available under CC BY-SA 4.0 & SATA ; additional terms may apply.