1 条题解
-
0
「AHOI2022」排列 题解
算法思路分析
核心数学洞察
循环值的本质:排列的循环值等于其所有循环长度的最小公倍数(LCM)。
证明思路:
- 排列的幂运算在每个循环上相当于循环移位
- 当且仅当每个长度为的循环满足
- 即是每个循环长度的倍数
- 因此最小的就是所有的LCM
置换的循环分解
将排列视为映射,可以得到若干不相交循环:
- 每个循环:
- 循环长度
- 原排列的循环值
交换操作对循环结构的影响
情况一:同循环内交换()
若在同一循环中,交换和会分裂该循环:
- 原循环:
- 交换后分裂为:和
- 但此时和仍在同一连通分量,
情况二:不同循环间交换(产生贡献)
若在循环(长度),在循环(长度),交换后:
- 和合并为长度为的新循环
- 新排列循环值 =
高效算法设计
步骤1:循环检测
- 使用DFS或迭代法找出所有循环
- 记录每个循环的长度和元素归属
- 时间复杂度:
步骤2:LCM预处理
- 对每个循环长度进行质因数分解
- 维护全局LCM的质因数分解形式
- 便于快速计算"移除某两个循环后的LCM"
步骤3:贡献计算优化
关键观察:相同长度配对的循环对贡献相同
设循环长度频次数组为,则:
- 对于长度:有个交换对
- 对于长度:有个交换对
每对的贡献值:
$$\text{贡献} = \text{LCM}\left(\frac{\text{全局LCM}}{\text{LCM}(L_a,L_b)}, L_a+L_b\right) $$步骤4:模运算处理
- 使用费马小定理计算模逆元
- 质因数分解形式下便于模运算
- 最终结果对取模
复杂度分析
- 循环检测:
- 质因数分解:
- 贡献计算:,其中为不同循环长度的个数
- 由于,实际效率很高
- 总体:,可处理
算法亮点
- 数学转化:将排列问题转化为数论问题
- 批量处理:按循环长度分组,避免枚举
- 质因数技巧:LCM的质因数分解形式便于快速计算
- 组合计数:利用对称性减少计算量
实现要点
- 使用vector存储循环信息
- 用map记录长度频次
- 质因数分解预处理到
- 注意整数溢出,及时取模
这种解法充分利用了排列的代数结构和数论性质,实现了从到的优化。
- 1
信息
- ID
- 3119
- 时间
- 1500ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者