常见哈希碰撞概率分析

算法竞赛里,哈希是常用算法,且往往会引入随机性(或者对于判题程序而言随机的行为)。

了解这些套路,并且讨论他们的碰撞概率,是非常有趣而且有帮助的一件事!

字符串 - 多项式哈希

字符集大小不限,对于任意字符串 \(S = (s_1, s_2, \dots s_n)\),我们为其构造一个多项式 \(H(x)\)

\[H(x) = s_1x^{n - 1} + s_2x^{n - 2} + s_3x^{n - 3} \dots + s_n \]

由于带着多项式计算很慢,我们发现可以取大质数 \(P\),以及一个随机固定值 \(b \in [1,p)\)
最终将 \(H(b) \pmod P\) 的值作为这个字符串的哈希值。

单次碰撞概率

给定两个 不同的 字符串 \(S_1, S_2\),长度分别为 \(n,m\ (n \ge m)\),其哈希值分别为 \(H_1(b),H_2(b)\)

我们认为发生碰撞,当且仅当 \(H_1(b) \equiv H_2(b)\),希望分析其概率:

  • 不妨两式相减,得到新的多项式 \(T(x) = H_1(x) - H_2(x)\)
  • 这一多项式的度数不超过 \(n\)

根据 Schwartz-Zippel 引理,对于一个非恒为零的多项式,其总度数为 \(d\),如果我们从 \([1,p)\) 中随机挑选一个数 \(b\),代入多项式后,其值为零的概率 \(\le d/P\)

也就是说,如果 \(b\) 对于数据/判题程序而言随机选取(对我们可以硬编码),则 \(H_1(b) = H_2(b)\) 的碰撞概率不超过 \(n/P\)

在“多模哈希”的情况下,如果我们选取了 \(c\)\((P,b)\),它们的碰撞概率相乘,为 \(n^c / \prod P_i\),变得更小了。

总体碰撞概率

称单次比较的碰撞概率为 \(n/P\),在给定了 \(t\) 个串的情况下,相互之间需要进行 \(\binom{t}{2}\) 轮比较,希望都没有碰撞。

我们先直接使用布尔不等式 Union Bound 进行宽松估计(已经足够使用),碰撞的概率不超过:

\[\Pr[\text{WA}] \le \frac{t(t-1)}{2} \cdot \frac{n}{P} \approx \frac{t^2 n}{2P} \]

这样就可以考察需要多少字符串,来使得你的代码无法通过 任何测试点

\[\frac{t^2 n}{2P} \approx 100\% \implies t \approx \sqrt{\frac{2P}{n}} \]

值得提醒的是,如果有 \(50\) 个测试点,那么单个测试点只需要 \(\le 5\%\) 的概率就会让你输掉比赛,可见单模数的危险。


如果允许理想地认为字符串的碰撞之间相互独立,还可以分析出更好的结果,单次无碰撞的概率为 \(1 - n/P\),则最终没有碰撞的概率是:

\[P[\text{AC}] = (1 - n/P)^{t^2/2} \]

由于我们往往使 \(n/P\) 足够小,此处利用 \((1 - x) \approx e^{-x}\) 进行毛估估:

\[\Pr[\text{AC}] \approx e^{-\frac{t^2 n}{2P}} \]

于是出现碰撞的概率不超过下式,这是更加紧的一个界(虽然对算法比赛而言不实用):

\[\Pr[\text{WA}] \le (1-e^{-\frac{t^2 n}{2P}}) \]

可重集 - 线性同余哈希

支持插入、删除元素;支持快速查询两个可重集是否一样。我们有至少 \(3\) 种做法,均在模意义下进行:

  • 乘法哈希:取大质数 \(P\),将元素的值映射到随机值 \([1,P)\),随后计算乘积。
  • 加法哈希 1:将元素的值映射到随机值 \([1,2^{64})\),随后计算加和。
  • 加法哈希 2:取大质数 \(P\),将元素的值映射到随机值 \([1,P)\),随后计算加和。

结论是:都不错,但加法哈希 1 又快又好。我们先说明加法哈希的单次碰撞概率(总体碰撞概率的分析方法可参照前文)。

由于值进行了随机映射,看似概率应当均能分析为 \(1/V\) 的值域倒数形式,但实际上输入数字的出现次数是可以被构造的。

加法哈希

设数值 \(x\) 被映射为 \(h(x)\),集合 \(A,B\) 不相等,其中 \(x\) 分别出现了 \(c_A,c_B\) 次,频数差 \(\Delta = |c_A - c_B|\),对于输入可任意构造。

碰撞条件为线性同余方程 \(H(A) \equiv H(B) \pmod{2^{64}}\),移项,再将无关项写为 \(C\),得到:

\[\Delta \cdot h(x) \equiv C \pmod{2^{64}} \]

因此可知方程的解数取决于 \(\gcd(\Delta, 2^{64})\),比赛环节下一般最坏可以被构造到 \(\Delta \approx 2^{20}\)

此处自然溢出的碰撞概率最坏为 \(1 / 2^{40}\)。而如果选择了一个大质数 \(P\),则可以将概率变为 \(1/P\)

乘法哈希

我们假设 \(H(A) = h(x)^{c_A} \cdot V_A\)\(H(B) = h(x)^{c_B} \cdot V_B\),其中 \(V_A,V_B\) 是其他项的乘积。则碰撞条件:

\[h(x)^{c_A} \cdot V_A \equiv h(x)^{c_B} \cdot V_B \pmod P \]

不妨设 \(c_A > c_B\),且令 \(C =V_B \cdot V_A^{-1} \pmod P\),改写碰撞条件为:

\[h(x)^{\Delta} \equiv C \pmod P \]

随后由于存在原根 \(g\),改写 $h(x) \equiv g^u $ 与 \(C \equiv g^v\) 可得到:

\[g^{u \cdot \Delta} \equiv g^v \pmod P \]

明显这里指数位置是“相同”的,在 mod 群的阶的意义下,有线性同余方程:

\[\Delta \cdot u \equiv v \pmod{P-1} \]

也就是说,方程的解数取决于 \(d = \gcd(\Delta, P-1)\),然而此处 \(P-1\) 总归是一个偶数,故不及加法哈希来得好。

posted @ 2026-08-19 01:52  Aurora5090  阅读(8)  评论(0)    收藏  举报