[学习笔记 #5] 哈希
[学习笔记 #5] 哈希
下面 [ ] 起来的是我还不确定的。
前言
从今年暑假到现在(2024.11.13),考了多少道哈希,我一道都没场切。前年 CSP-S T3 星战没想出哈希做法,去年 CSP-S T2 又没想出哈希做法。满满的黑历史……
早就想总结了,没时间。今天忍不住了。
哈希表
- 哈希表和下面说的哈希应该不是一回事。
- 概括:缩小范围。可以用来存储哈希值。
- 具体实现:
- 当集合 \(A\) 较大时,用一个函数 \(f : A \rightarrow B\) 把 \(A\) [映射] 到一个较小的集合 \(B\)。
- 查找时给出 \(B\) 中的元素,对应回 \(A\) 中的元素。
- 但是 \(B\) 中的一个元素可能对应 \(A\) 中的多个元素,即哈希冲突(或称哈希碰撞)。
- 两种解决方法:
- 让 \(B\) 中的每个元素挂一串(\(A\) 中的)元素。查找时遍历这一串。
- 让 \(B\) 中的每个元素只对应一个(\(A\) 中的)元素。那么每添加一个(\(A\) 中的)元素时,如果对应的(\(B\) 中)元素没有对应元素,就对应上,否则接着找,直到找到一个还没对应的,对应上。
- 两种解决方法:
- 实际使用:
- 可以用 map 或 unordered_map。map 带 \(\log\),但 unordered_map [[可能会被卡]]。
- 可以用 pb_ds 里的哈希表。
过渡:用哈希解决判定性问题
- 接下来的哈希用于解决 判定性问题。
- 采用哈希的原因:常规方式难以判定。
- 方法:
- 我们找 充分条件或必要条件(不是充要条件) 来判定,使用哈希来简化问题。
- 通过随机和多次判定来降低错误概率。
- 可以从原命题或 [[原命题的否定]] 两方面考虑。
- 要 判断是否是某种情况,就要先选择哈希的方式(要有针对性),再得到这样哈希的话这种情况的值是多少或是什么情况,最后判断真实的哈希值是否满足条件。
不知道归到哪里去的技巧
- 四次方([可能] 要取模)。[使哈希值更离散。]
- 双哈希。
- 多次哈希。
集合哈希
-
通过运算的交换律来 [表现] 集合的 [无序性]。
-
可以转化为序列哈希:
-
方法一:
- 对集合中每个值,记录它的出现次数,记到一个序列(桶)上(给值固定了顺序)。
- 可重集:就是这样。
- 不是可重集:出现次数是 \(0\) 或 \(1\)。
- 对这个序列跑序列哈希。
- 对集合中每个值,记录它的出现次数,记到一个序列(桶)上(给值固定了顺序)。
-
方法二:
- 对集合排序(规定某种顺序,不一定从小到大),跑序列哈希。
-
Sum Hashing
- 哈希值表示整个集合。
- \(h(S) = \sum _ { x \in S } h' ( x )\)。
- \(h'\):对每个 \(x\) 赋一个随机值(相同的 \(x\) 赋的值相同)。
- 一个性质——判断集合中每个数的出现次数是否都是 \(k\) 的倍数(出现次数为 \(0\) 也可以):
- 求和有对取模很友好的性质:如果一个数值的出现次数 \(\bmod k = 0\),那么它的哈希值加起来 \(\bmod k\) 也为 \(0\)。如果每个数值的哈希值之和 \(\bmod k = 0\),那么整个集合的哈希值(每个数的哈希值加起来,即每个数值的哈希值之和加起来)就也 \(\bmod k = 0\)。因此原命题能推出 Sum Hashing 的值 \(\bmod k = 0\),那么后者就是前者的必要条件。
- 看 Sum Hashing 的值 \(\bmod k\) 是否为 \(0\)。
- 如果不为 \(0\) 则说明集合中 每个数的出现次数都是 \(k\) 的倍数 一定不成立。
- 如果为 \(0\) 则说明 ~ 可能成立。
- [蒙特卡罗判定]。
- 随机较多遍之后错误率就小到可以接受了。
- 题、错误率分析见:CF1746F Kazaee。
Xor Hashing
- 二进制 Xor Hashing [较常见]。
- \(k\) 进制 Xor Hashing。
- 每一位分别相加,不进位,分别对 \(k\) 取模。
- 哈希值 一般 不表示整个集合,只表示每个元素出现次数 \(\bmod k\) 是否为 \(0\)。
- 如果集合中每个元素的出现次数都 \(\leq k\),Xor Hashing 表示的就是整个集合。
- 本质:
- 把很多遍 取模的 Sum Hashing(就是上面写的 Sum Hashing 的“一个性质”部分)压到一起跑。因为每一位是独立的,每一位都相当于一次取模的 Sum Hashing。
- 错误率:
- 二进制 Xor Hashing 的话,在 [[int 或 long long]] 范围内随机,[一般] 这样跑一遍的错误率就刚好小到可以接受了。
- 相比 Sum Hashing 的优势:
- (二进制 Xor Hashing)二进制压缩,去掉了跑很多遍带的大概一只 \(\log\)。
- 异或性质优美,有时有妙用。(下面是二进制的,[更高的] 进制我不知道)
- 重复直接消掉:
- 树上简单路径的异或和:直接算到根的异或和,异或起来即可。
- [异或线性基]。(我还不清楚正确率)(咕咕咕)
- 重复直接消掉:
序列哈希
- 把下标加入计算中,从而 [表现] [有序性]。
- 字符串哈希。(多项式哈希。)
- 作用:判定相等。
- 可以预处理 Base 的幂来 \(O(1)\) 取出一段的哈希值。
- 双哈希。
树哈希
还不会呜呜呜。
数据结构维护哈希值
- 哈希表。
- 其他数据结构。
咕咕咕。
以后来放题。
参考
2024.11.13