杂论 - 数据生成
序列
- 生成随机排列
- 生成长度 \(n\),值域 \(m\) 的不重复随机序列
- 不断生成直到不重为止,可以证明是均匀随机的,复杂度 \(O(n\log n)\)
- 当 \(m\le 2n\) 时生成长度为 \(m\) 的排列然后取前 \(n\) 项,复杂度 \(O(n)\)
- 生成指定和的序列
- 转化为生成不重前缀和
树
- 选取 \(i/2\) 作为父亲,得到完全二叉树
-
咕咕咕! \([1,i)\) 随机父亲,可以证明 树高 \(O(\log n)\)
- \([i-B+1,i)\) 随机父亲,对于 \(n = 2 × 10^5\) 的数据可以设定 \(B = 10\) 或 \(20\),这样生成
的树比较适合测试启发式合并 - 生成 Prufer 序列
- 从所有有标号无根树中等概率随机,这种生成方式还可以固定每个点的度数
- 链与完全二叉树的结合
- 取前 \(B_1\) 个点构造完全二叉树,将后面每 \(B_2\) 个点连成一条链,连接在前 \(B_1\) 个点上。一种常见的取值方式是取 \(B_1 = ⌊2\sqrt{n}⌋, B_2 = ⌊\sqrt{n}⌋\)。这样既有较长的链,所有点的轻儿子大小和又为 \(O(n \log n)\)
仙人掌
- 生成一棵点数为 \(2n\) 的树作为圆方树,将其黑白染色,取点数少的颜色作为圆点,其余作为方点并删掉方点叶子
- 这样环长可以简单的通过树的形态,即每个点的度数来调整
- 生成其生成树,再在树上加边,每个点以指定概率向上走
- 这样生成出的仙人掌环长较小,可以手动添加大环
- 生成其生成树,并随机两点加边
- 这样生成出的仙人掌环长不稳定(方差大),环的个数少,可以生成出比较大的环
图上最短路
构造网格图或链套菊花卡掉 SPFA。
- https://www.cnblogs.com/luckyblock/p/14317096.html
- https://www.zhihu.com/question/292283275/answer/484871888
括号序列
对于括号序列 \(s\),\(a\) 为其前缀和。
- 定义 \(s\) 平衡,当且仅当 \(a_n = 0\)。
- 定义 \(s\) 合法,当且仅当 \(s\) 平衡,且任意 \(a_i\ge 0\)。
- 定义 \(s^R\) 表示 \(s\) 反转后的串。
- 随机一个平衡串 \(s\),\(\Phi(s)\) 对其变换。
- 找到 \(s\) 的最短非空平衡前缀,将 \(s\) 表示为 \(lr\) 的形式
- 若 \(l\) 合法,\(\Phi(s)=l\Phi(r)\)
- 否则 \(l\) 一定可以表示为 \() t (\) 的形式,\(\Phi(s)=(\Phi(r))t^{R}\)。
证明:对于任意缺陷度组成的平衡串集合,和合法串集合 形成双射。详见论文。
哈希冲突
序列哈希
-
生日悖论
- 悖论有两种含义:
- 与自身前提和部分公理相矛盾。
- 与生活常识或经验相矛盾。
- 这里的生日悖论就是这种:假设班里有 \(57\) 个人,且各个人出生月日 均匀独立随机,那么班里有至少两个人出生月日相等的概率 \(>99\%\)。
-
咕咕咕!\(P(n)=1-\prod_{i=1}^{n-1}(1-\dfrac{i}{m})≈1−e^{-\frac{n(n-1)}{2m}}\)。
- 也就是在 \(n=O(\sqrt{m})\) 时,概率已经 \(\ge 50\%\) 了。
- 悖论有两种含义:
-
哈希值:\(\operatorname{hsh}(s)=\sum_{i=1}^n B^{i-1}\operatorname{ord}(s_i)\bmod m\),\(\operatorname{ord}(c)\) 表示在码表中的位置。
-
单模数。双模数:\(\gcd(m_1,m_2)=1\) 则值域可以看作 \(m_1m_2\)。自然溢出:\(m=2^{64}\)。
对自然溢出构造冲突:
- \(B\) 为偶数,\(B^{64}\bmod m=0\),只有前 \(64\) 位有效。
- \(B\) 为奇数,考虑 Thue-Morse 序列。
记 \(s^T\) 表示将 \(s\) 01 反转得到的序列,记 \(f(s)=\operatorname{hsh}(s^T)-\operatorname{hsh}(s)\),\(d=\operatorname{ord}(0)-\operatorname{ord}(1)\),\(|s|\) 表示 \(\log_2 s\) 的长度。则 \(f(0)=d\),\(f(s+s^T)=(1-B^{2^{|s|}})f(s)\)。注意到 \((1-B^{2^{|s|}})=(1-B^{2^{|s|-1}})(1+B^{2^{|s|-1}})\),后一项是 \(2\) 的倍数,前一项有可以继续递归下去,那么 \(f\) 一定可以被 \(2^{|s|(|s|+1)/2}\) 整除。在 \(|s| = 11\) 时即可构造冲突。
树哈希
- 一种较为正确的树哈希方法是括号序,使用最小表示法的思想,让同构的树得到的括号序相同。一个子树的哈希值可以通过如下方式递归求出:
- 求出所有儿子的哈希值,以(哈希值,子树大小)为关键字排序(排序关键字中加入子树大小,是为了防止子树中因生日悖论产生哈希值相等的、不同大小的子树,影响结果)
- 将所有儿子的括号序相接,在最外层添加一对括号,得到的序列就是它的括号序哈希值
- 还有一种 \(Θ(n)\) 哈希广为人知。
- 生成序列 \(W_1, W_2, \ldots , W_n\),一般采用质数序列或随机序列,点 \(u\) 的哈希值计算如下:
- \(h_u=W_{\text{siz}_u}(1+\sum_{v\in \text{son}_u}h_v)\)。
- 整棵树的哈希值之和所有结点到根结点的链上的子树大小组成的序列有关,Hack:
- 生成序列 \(W_1, W_2, \ldots , W_n\),一般采用质数序列或随机序列,点 \(u\) 的哈希值计算如下: