G. Modular Sorting
Codeforces 第 1034 轮 (Div. 3) G
问题
给定一个整数 () 和一个由严格小于 的非负整数组成的数组 。
你需要处理两种类型的查询:
i x: 赋值 (此操作会持久更新数组)。k: 在一次操作中,你可以选择任意元素 并赋值 。判断是否存在一个这样的操作序列(可能为零次),可以使数组变为 非递减 的(即 )。
注意:类型 2 的查询是 假设性 的 — 它们不会修改数组。类型 1 的查询是 持久性 的,会永久改变数组。
题解
基本思想
对于一个参数为 的类型 2 查询,我们的目标是判断是否存在一组非负整数 使得:
并且得到的数组 是非递减的。
模算术与循环子群
令 。当我们重复应用操作 时, 可以达到的值都位于同一个 模 的陪集 中:
这意味着 每个元素在任何次数的以 为步长的操作下,其模 的余数保持不变。
因此,任意两个元素 和 之间的最小差值为 。
通过模差分判断可行性
那么, 的所有可达值构成了这个长度的循环群。为了检查我们是否能将值重新排列成非递减顺序,我们使用一个关键指标,该指标衡量从左到右需要多少模“增量”。
我们定义:
其中
- for
这个表达式捕捉了在模 下从 移动到 所需的“正模步长”。
可行性条件:
对于一个给定 的类型 2 查询,令 。那么:
当且仅当 时,数组可以变为非递减。
如果 ,所需的模位移将会环绕 — 违反了非递减约束。
类型 1 查询的高效更新
当处理一个类型 1 查询 (i x) 时,我们需要为 的 所有因子 更新指标 ,因为任何未来的查询都可能使用一个 使得 。
将 更改为 最多影响 中的两项:
- 如果 ,差值
- 如果 ,差值
对于每个这样的 ,我们:
- 减去对 的旧贡献
- 将 更新为
- 加回新的贡献
为了保持效率,我们:
- 预计算 的所有因子
- 为每个 存储
- 使用直接访问仅更新受影响的项
总结
- 每个值 只能在其模 的同余类内移动。
- 为了确定类型 2 查询的可行性,我们使用模步长和 。
- 条件 保证了序列可以变为非递减。
- 高效处理类型 1 更新确保了系统的性能。