之前打比赛多次担心写单哈希被卡,但 N 神之前说他高中打过的所有比赛,但凡是字符串的题写 unsigned long long 自然溢出从来没被卡过。我信以为真,认为现在已经没有人素质差到卡别人单模哈希。后来我打了一些 AtCoder 的比赛也写了很多 ull 自然溢出也没事。直到 这场CF N 神 B 题 ull 自然溢出被卡到裂开,以为思路错了,直到赛后才发现是单哈希被卡了。
鉴于以上惨痛的经历,我决定学习一下毒瘤的卡单模数哈希的方法,来警示自己以及与 N 神心态类似的人:不要管出题人卡不卡,反正写双哈希就对了。(警钟撅烂(逃
II. 模 10^9 级别的大质数哈希
其实单模 10^9 级别的大质数哈希非常好卡,我们只需要随机一个长度为 10^5 级别的只包含小写字母的字符串 s,再任取一个大小为 100 左右的子串长度 k,那么 s 的所有长度为 k 的子串中大概率会存在哈希冲突的字符串。
那么概率到底有多大呢,我们可以使用生日悖论的方法来计算。
字符串 s 的长度为 k 的子串总共有 26^{k} 种可能,当 k = 100 时 s 的任意两个长度为 k 的子串几乎不可能相等,所以我们按照长度为 k 的子串均不同来考虑。(其实计算这个本身也是生日悖论)
因为 s 中总共有 10^5 - k + 1 个长度为 k 的子串,设 p 为模数,则第 1 个子串的哈希值不跟之前重复的概率为 \displaystyle{\frac{p}{p}},第 2 个子串的哈希值不跟之前重复的概率为 \displaystyle{\frac{p - 1}{p}} ,第 n 个子串的哈希值不跟之前重复的概率为 \displaystyle{\frac{p - n + 1}{p}}。所以出现至少两个长度为 k 子串哈希冲突的概率为 \displaystyle{1 - \prod\limits_{i = 1}^{10^{5} - k + 1} \frac{p - i + 1}{p}}。当 p = 10^9 + 7, k = 100 时计算上式的值约为 0.9931958400。