模型
给定一个序列,分成若干段,分段有一定的限制条件,并需要一定的费用,问怎样分段才能在满足限制条件的情况下,使费用最小。
条件
状态转移方程类似于:dp[i] = dp[j] + (x[i] - x[j]) * (x[i] - x[j])。无法转化成dp[i] = f[j] + x[i]的形式。
抽象
将dp[i] = dp[j] + (x[i] - x[j]) * (x[i] - x[j])化成
[(dp[j] + sum[j] * sum[j]) - (dp[k] + sum[k] * sum[k])] / 2(sum[j] - sum[k]) <= sum[i]的形式,即斜率的形式。
解决
- 如果ij的斜率>=sum[i],那么 j 点比 i 点更优,删除 i 点
- 设k < j < i,若 ij 斜率小于 jk 斜率,画出线段 kj , ji , ki,发现正好是一个上凸的三角形,并且 ki 的斜率大于 kj 和 ji 的斜率,可以将 j 点删除。
方法
- 用一个单调队列来维护解集
- 假设队列中从头到尾已经有元素a b c
- 从队头开始,当 i 点要求解时,如果 ba 的斜率小于sum[i],将a点删除,即a出队,此时dp[i]等于从 i 到head的数的和
- 当d要入队的时候,若 dc 的斜率小于 cb 的斜率,就将c点删除。直到找到 dx 斜率大于等于 xy 为止,并将d点入队
例题
- 杭电3507
- 杭电2829
- 杭电3480
- 杭电2993
- 杭电3045