3.1 - Fraudulent Blocks
Jason 笔记
核心思路
- 遍历所有块大小
- 假设签名长度 = L。
- 可能的块大小
S∈ [1, L]。
- 如何分组
- 对每个签名:
- 按大小 S 切分成块(最后不足 S 的部分 → 尾巴)。
- 尾巴必须相同,才能在同一组。
- 对块序列,用「循环最小表示」来作为标准形态,确保不同重排方式能映射到同一组。
- 组合键 =
尾巴 + 块序列的标准形态。
- 计算可疑度分数
- 遍历所有分组,统计每组大小。
- 分数 = 所有组大小的连乘积。
- 选择最佳结果
- 比较所有块大小对应的分数。
- 返回最大分数对应的
(S, 分数)。 - 如果有多个 S 结果相同,返回任意一个。
伪代码
- 初始化
- 获取签名长度
sign_length。 - 设置最佳块大小
best_block_size = 1。 - 设置最佳分数
best_score = 1。
- 遍历所有可能的块大小
- 从
1到sign_length: - 建立空的哈希表
groups,用来分组。 - 对每个交易:
- 取出签名字符串
sign。 - 按
block_size切分签名 → 得到若干块,放入blocks(保持有序)。 - 记录尾巴部分(不足一个块的字符)。
- 生成分组键
key = 尾巴 + 块序列拼接结果。 - 在
groups中: - 如果没有这个键,初始化为 0。
- 然后
+1,表示该组里多一个签名。 - 计算当前分数
- 初始化
suspicion = 1。 - 遍历
groups中每个组的大小,做乘积。 - 更新最优解
- 如果
suspicion > best_score: - 更新
best_score。 - 更新
best_block_size。
- 返回结果
- 返回
(best_block_size, best_score)。
3.2 - Rectification
Jason 笔记
核心思路
- Step 1: 遍历所有候选函数。
- Step 2: 对每个函数,计算所有交易的哈希值。
- Step 3: 确定表大小 =
max(hash_values) + 1。
- Step 4: 模拟线性探查的最坏情况,求出 MPCL。
- 如果碰撞太多,无法插入 → MPCL = 表大小。
- 否则,统计最大连续冲突链的长度。
- Step 5: 在所有函数中找到 MPCL 最小的函数。
关键观察
- 最坏情况 = 所有哈希值按照“最糟糕的顺序”插入。
- 实际上不需要枚举所有插入顺序(复杂度太高)。
- 只需观察:
- 某个位置
i有多少个元素映射到它(记为k)。 - 如果
k > 1,意味着至少会产生探查链。 - 线性探查中,冲突会“连锁”影响后续槽位,因此最大冲突段长度决定了 MPCL。
🤔 我代码过于猎奇了,这里就不写伪代码了