基础算法——异或哈希算法 学习笔记
异或哈希算法
思想
我们关注一个区间内出现了什么数字。
因此,我们对每一个数字赋一个随机权值,
然后对这个权值进行一系列操作,例如前缀 \(\operatorname{xor}\) 等。
对于两个序列,通过 Hash 的方式判断即可。
同时,也可用于满足某些条件的子序列数量的问题。
我们可以通过 Hash 的方式找到前面满足某些条件的数,来匹配子序列。
例题
区间判断
AtCoder [ABC250E] Prefix Equality
题目描述:
给定序列 \(A,B\),询问 \(A\) 的前 \(x\) 个数和 \(B\) 的前 \(y\) 个数去重后是否相同。
做法:
我们对每一个数赋一个随机权值,
将序列中第一次出现的这个数赋为权值,后面的都赋为 \(0\)。
那么我们只需要判断两个前缀异或和是否相同即可。
使用 mt19937_64
生成比较强的随机数,冲突概率较小。
- 代码
using u64 = uint64_t; mt19937_64 rnd_big(114514); int n; u64 W[N]; u64 A[N], B[N]; unordered_set<int> appA, appB; unordered_map<int, u64> hashing; u64 get_hashing(int x) { return hashing.count(x) ? hashing[x] : hashing[x] = rnd_big(); } void Main() { cin >> n; for (int i = 1; i <= n; ++i) { int x; cin >> x; if (appA.count(x)) A[i] = A[i - 1]; else A[i] = A[i - 1] ^ get_hashing(x), appA.insert(x); } for (int i = 1; i <= n; ++i) { int x; cin >> x; if (appB.count(x)) B[i] = B[i - 1]; else B[i] = B[i - 1] ^ get_hashing(x), appB.insert(x); } int q; cin >> q; while (q--) { int x, y; cin >> x >> y; puts(A[x] == B[y] ? "Yes" : "No"); } }
区间计数
变种
矩阵乘积
来源是 CSP-S 2023 消消乐,用处不大。
但是这引出了类似异或和的一个特有做法。
设有一个群 \((G,\cdot)\),将元素分为入元素和出元素,令入元素和出元素互为逆元。
那么,如果一个区间 \([l,r]\) 的某种运算的前缀和为单位元了,
那么意味着这个区间的元素可以互相抵消,我们可以将前缀和放到 map
里面记录,
对于每一个 \(S(r)\) 对应的 \(S(l)=S(r),l<r\) 就可以统计满足条件的子区间数量。
本文来自博客园,作者:RainPPR,转载请注明原文链接:https://www.cnblogs.com/RainPPR/p/18572452
如有侵权请联系我(或 2125773894@qq.com)删除。