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。

posted @ 2024-06-18 20:31  PYD1  阅读(12)  评论(0)    收藏  举报