一种简单的子串 Hash 取模优化方法

我们经常用 hash 表来定位子串,或者希望 hash 有更高的正确率,此时 32 位的模数是不够的。通常使用的方法是模两个小素数,而这并不非常方便。

注意到模数是任取的,我们取素数 \(M = 2^{61}-1\) 作为模数。

此时对 \(M\) 取模相当容易,只要把 \(x\) 的高 \(61\) 位和低 \(61\) 位相加,再判断是否大于等于 \(M\) 即可。

对于底数 \(b\) 我们再预处理出 \(-b^i \bmod M\),就可以快速提取区间 hash 了。由于存在将两个 64 位的数相乘并存入两个寄存器中的指令,计算乘法速度并不慢。

const ull HashM = (1ULL << 61) - 1;

ull red(u128 x) {
  ll v = ull(x & HashM) + ull(x >> 61) - HashM;
  return v + (HashM & (v >> 63));
}
posted @ 2022-04-28 11:37  RiverHamster  阅读(174)  评论(0编辑  收藏  举报
\