Barrett 约减
这东西原理我并不清楚啊。
大概意思就是说,因为除法很慢,所以我们想个办法优化除法。
\[\frac xm=\frac x{2^k}\times\frac{2^k}m\approx\frac{x\lfloor\dfrac{2^k}{m}\rfloor}{2^k}
\]
我们提前计算 \(\lfloor\frac{2^k}m\rfloor\)(似乎这里应该是上取整),这样,计算除法就只需要一次乘法和一次右移操作。
当然这样可能有误差,如果我们记 \(x\) 的上界是 \(n\),那么当 \(2^k>n(m-1)\) 的时候是没有误差的,当 \(2^k>n\) 可能产生 \(1\) 的误差,对应到取模上就是 \(m\) 的误差。
所以我们最后还要重新真的取模一次。
代码如下:
int modm,modp;
void init(int p){
modm = (__int128(1) << 64) / p,modp = p;
}
inline ll mod(ll x){
return x - ((__int128(x) * modm) >> 64) * modp;
}
实践发现,加了 barrett 约减的输入模数取模,在开 O2 的情况下跟固定模数基本一样快(前者 1581,后者 1753),不开 O2 barrett 慢一些(前者 4215,后者 3666)。本机测试 ARC114 C。

浙公网安备 33010602011771号