哈希与“特征量”

哈希

这部分比较地简单。

P6688 可重集

考虑定义哈希函数为 \(\sum bas^{a_i}\),这个函数是支持区间加的。本质上是因为 \((+,\times )\) 有结合律。
判断两集合是否相等的话考虑各减去其最小值即可。

基于哈希的后缀排序

对于每个后缀,考虑提取前 \(n/2\) 个字符,形成 \(n/2\) 个等价类,这里用哈希+哈希表处理。
我们要做的就是对于每个等价类内部排序和对每个等价类排序。递归子问题,规模是 \(O(n/2)\)
每层的规模之和都是 \(O(n)\),一共 \(O(\log n)\) 层,所以复杂度是 \(O(n\log n)\)
zak 表示运用了整体二分的思想。

P10992 [蓝桥杯 2023 国 Python A] 最长同类子串

先二分,考虑判断两个区间是否等价。这个很典,两个区间的等价可以表示为 \(d_i=i-pre_i\) 序列相同。
这个是容易维护的。

CF1479D Odd Mineral Resource

经典的 xor-hash 处理奇数次出现,考虑如何找这么一个 x。
如果已知存在这样一个 x,但是不知道是哪个可以考虑集合的二分,然后这个可以放到线段树上。
考虑对值域开可持久化线段树,每个树上的点维护根到该点路径的信息即可。

CF452F Permutation

考虑枚举中间的那个数,那么,如果存在等差子序列那么就存在 \(a_i-k,a_i+k\) 分居同一侧。
考虑正难则反。如果不存在,那么对于所有 \(k\)\(a_i-k,a_i+k\) 都所处位置相同,考虑用 \(0,1\) 代表两侧。
判断序列的相同考虑哈希,我们从左往右扫,线段树维护哈希即可。

ABC274Ex XOR Sum of Arrays

相当于求最小的 \(i\) 满足 \(a_{l_1+i}\oplus a_{l_2+i}\oplus a_{l3+i}\neq 0\)。显然二分,现在考虑设计哈希。
我们常见的字符串 Hash 不支持异或操作。因为乘法对异或不具有分配率,即 \((x\oplus y)\times B\neq xB\oplus yB\)
但是异或是不进位加法,也就是每位相当于做模 \(2\) 加法,现在就具有分配率了。那么乘法相当于 AND。
考虑将每个数设计成 \(w\) 维向量,乘法相当于乘矩阵。考虑随机一个 \(w\times w\) 的矩阵 \(B\) 出来。
那么一段序列的哈希值就是 \((((a_1B\oplus a_2)B\oplus a_3)B\dots\oplus a_m)B\)。其中 \(a\) 是向量。
我们矩阵乘法是 \((\oplus,\text{AND})\) 的,这个可以采用位运算优化到 \(O(w^2)\),然后向量乘矩阵是 \(O(w)\) 的。
常见优化转二分为倍增,只需要预处理即可,预处理所有 \([i,i+2^p-1]\) 的哈希值和所有 \(B^{2^p}\)
预处理过程考虑用分配律拆成两半就行了。中途过程是向量乘矩阵,复杂度是 \(O(nw\log n)\)
补充一点,位运算优化的写法是枚举 A 的每个元素 \(A_{i,k}\),然后若其为 \(1\) 就让 \(C_i\) 异或上 \(B_k\) 就行了。
如果是加法用字符串 Hash 即可。只不过为了有分配率换成了向量,用 \((\oplus,\text{AND})\) 矩乘。
很有 Edu 意义。

特征量(不变量)

特征量就是表示特征的量。

CF1630D Flipping Range

相当于给 \(len=\gcd(\{B_i\})\) 的区间异或 \(1\)。那么按照模 \(k\) 分组,每组的异或和相同。
这就是‘特征量“。也可以叫做不变量。

ARC135D Add to Square

黑白染色。那么黑点的变化量之和 = 白点的变化量之和。相当于序列上的模 2 分组。
由于答案求的是绝对值,考虑给黑点全部取相反数,然后加法变减法。那么现在加法对总和没有实际影响、
现在的限制就是有且仅有每行每列的和不变。设每行,列总和是 \(h_i,w_i\),答案下界是 \(\max(\sum |w_i|,\sum|h_i|)\)
钦定 \(\sum |h_i|\) 更大。要取到这个下界那么若 \(h_i\) 为正那么其元素必须全部为正;反之同理。
因为 \(\sum h_i=\sum w_i\),所以你随便分 \(h_i\) 不会无解。在 \((i,j)\) 地方加上 \(x\) 然后 \(h_i,w_j\) 减去 \(w\) 称他们匹配。
然后因为 \(\sum |h_i|>\sum |w_i|\),所以你把 \(h_i,w_i\) 同号的都给匹配了,然后现在剩下 \(h_i\) 有正有负。
对于负的随便转移出去一个列,然后正的再拿回来就行了。说的比较抽象。
最后记得把黑点取相反数取回来。

CF1672G Cross Xor

考虑 \(n,m\) 都为偶数的情况。考虑我们要反转 \((x,y)\),我们把所有 \(i=x\or j=y\)\((i,j)\) 全部操作一遍。
那么发现全部抵消,只反转了 \((x,y)\),所以全部矩阵都是合法的。
考虑其中一个为奇数,钦定 \(n\) 为奇数,我们先解决 \((n-1)\times m\) 部分,最后一行只需要全部数相同即可。
每次按照上述方法反转 \((x,y)\) 后,那么每列的异或和都会异或上 \(1\)。那么条件就是所有列的异或和相同。
上述两个情况容易计数。
考虑 \(n,m\) 都是奇数。那么每次操作后每行和每列都异或了 \(1\)。那么条件是所有行列的异或和相等。
构造的话直接解决 \((n-1)\times (m-1)\) 即可。考虑计数。考虑先枚举每行每列异或和等于多少。
枚举后,问题就转化为了有一张二分图,每个点有点权。对每条边,你可以选择将其两端的点权值异或 1。
问有多少种方案。这个可以对每个联通块分开处理,每个联通块的点权异或和必须要能调整为你枚举的 \(0/1\)
每个联通块内找生成树,非树边可以随意选择,树边的权值是固定的。设共有 \(c\) 条非树边,答案就是 \(2^c\)

以上三题的总结:给定向量集合 \(S\),要求找出这些向量的线性组合的一些性质。我们的解法都是观察出,一个向量能被组合出当且仅当其点乘上另一些向量后为 \(0\)

实际上,对于任意一个线性空间都是有该性质的。而其对应的线性空间是其“正交空间“。在OI中我们可以通过打表观察正交空间来猜测结论。

AGC006C Rabbit Exercise

注意到本题就是 NOIP 2021 方差。每次操作也就是交换差分。置换 \(k\) 次,这个用快速幂计算即可。

AGC052B Tree Edges XOR

考虑链怎么做,考虑做前缀和,如果不是在第一个节点操作就是交换前缀和的两个位置。
那么树也是一样的,考虑定根,然后把边放到点上,每个点点权定义为到根路径异或和。
但是有个问题就是如果操作到根节点,那么根节点的权值也要被交换,但事实上根节点的权值最后必须为 \(0\)
也就是说,我们任交换出来的话前缀和第 \(0\) 位不为 \(0\),需要异或掉这个数。
由于可以任意交换所以我们只需要判断集合是否相等。相当于判断第一个集合异或某数是否等于第二集合。
考虑如何求这个“某数”,考虑利用 \(n\) 为奇数的条件,那么这个数就是二者全部元素的异或和。
\((A_1\oplus B_1)\oplus \dots\oplus (A_{n=2k+1}\oplus B_n)=(A_i\oplus B_i)\)。奇数与异或,这个太典了。想到一个 ad-hoc 题。

posted @ 2025-02-08 19:42  s1monG  阅读(13)  评论(0)    收藏  举报