1 条题解
-
0
好的,我们来根据这个代码生成题解和算法标签。
算法思路
这是一个 环形 DP + 线段树维护矩阵乘法 的解法。
问题转化
题目要求:在一个长度为 的环上选择一些数,不能有连续 个或以上的数被选中,求最大和。
这是一个 环形 DP 问题,但直接做是 的,而 可达 ,需要支持修改,所以必须优化。
状态设计
设 表示考虑前 个位置,末尾连续选择了 个 的最大和()。
转移:
- 如果第 个不选:$f_{i, 0} = \max(f_{i-1, 0}, f_{i-1, 1}, f_{i-1, 2}, f_{i-1, 3})$
- 如果第 个选:
注意 时不能再选下一个(否则连续 个)。
矩阵形式
把 看作向量,则转移可以写成矩阵乘法:
$$\begin{bmatrix} f_{i,0} & f_{i,1} & f_{i,2} & f_{i,3} \end{bmatrix} = \begin{bmatrix} f_{i-1,0} & f_{i-1,1} & f_{i-1,2} & f_{i-1,3} \end{bmatrix} \times M_i $$其中
$$M_i = \begin{bmatrix} 0 & a_i & -\infty & -\infty \\ 0 & -\infty & a_i & -\infty \\ 0 & -\infty & -\infty & a_i \\ 0 & -\infty & -\infty & -\infty \end{bmatrix} $$这里 表示不可达。
环形处理
因为是环,我们枚举前 个位置的选择情况(即初始向量),然后做一次 的矩阵乘法,最后检查末尾状态与初始状态是否冲突(末尾连续选择个数 + 开头连续选择个数 < 4)。
代码中简化处理:直接枚举末尾状态 (0~3),然后取 中 的最大值,这样隐含了环形约束。
线段树维护
线段树每个节点存一个 的矩阵,表示该区间上的转移矩阵的乘积。
修改时更新叶子节点矩阵中的 ,然后向上合并。合并就是矩阵乘法( 用 , 用 )。
复杂度
- 初始建树:
- 每次修改:
- 查询:(直接取根节点)
代码注释摘要
tr[num][i][j]表示从状态 进入该区间,离开时状态为 的最大值。- 叶子矩阵构造:
- 选一个数:, , 加
- 不选: 加
- 查询时枚举环的“断点”状态(末尾状态 ),取合法值。
- 1
信息
- ID
- 5390
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者