1 条题解
-
0
题解:修整土路为单调斜坡(P3666)
一、题目分析
本题要求将给定的海拔序列调整为非递增或非递减序列,使得修改的总成本(各位置绝对差之和)最小。关键信息:
- 输入序列长度()
- 海拔高度()
- 目标序列需满足非递增或非递减
- 总成本为
二、解题思路
-
问题转化:
分别求解非递减和非递增序列的最小成本,取较小值。非递增问题可通过反转序列转化为非递减问题。 -
离散化优化:
由于范围大,将可能的值离散化为原始的去重排序集合,减少状态数。 -
动态规划:
- 状态定义:表示前个位置形成非递减序列,第个位置取离散化后第个值的最小成本
- 状态转移:枚举当前位置的可能值,确保序列单调性
三、代码解析
#include <iostream> #include <cmath> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #define LL long long using namespace std; const int INF = 0x3f3f3f3f; int dp[2][2333][2333]; // dp[0]:非递减,dp[1]:非递增 int a[2333]; // 原始海拔序列 int b[2333]; // 离散化后的序列 map<int, int> mp; // 离散化映射 int main() { int n; scanf("%d", &n); // 读取原始海拔序列 for (int i = 0; i < n; ++i) { scanf("%d", &a[i]); b[i] = a[i]; } // 离散化:去重排序 sort(b, b + n); int id = -1; for (int i = 0; i < n; ++i) { if (i == 0 || b[i] != b[i-1]) { id++; b[id] = b[i]; mp[b[i]] = id; // 记录值对应的离散化索引 } } // 初始化:第一个位置的所有可能值 memset(dp, INF, sizeof(dp)); for (int i = 0; i <= id; ++i) { dp[0][0][i] = dp[1][0][i] = abs(a[0] - b[i]); if (i > 0) { // 优化:取更优的前一个状态 dp[0][0][i] = min(dp[0][0][i], dp[0][0][i-1]); dp[1][0][i-1] = min(dp[1][0][i-1], dp[1][0][i]); } } // 动态规划求解非递减和非递增序列 for (int i = 1; i < n; ++i) { for (int j = 0; j <= id; ++j) { // 非递减序列:当前值≥前一个值 dp[0][i][j] = dp[0][i-1][j] + abs(a[i] - b[j]); if (j > 0) dp[0][i][j] = min(dp[0][i][j], dp[0][i][j-1]); // 非递增序列:当前值≤前一个值(通过反转序列转化) dp[1][i][j] = dp[1][i-1][j] + abs(a[i] - b[j]); if (j > 0) dp[1][i][j-1] = min(dp[1][i][j-1], dp[1][i][j]); } } // 取非递减和非递增的最小成本 printf("%d\n", min(dp[0][n-1][id], dp[1][n-1][0])); return 0; }
四、关键步骤解析
-
离散化处理:
- 将原始序列复制到并排序去重,得到离散化后的可能值集合
- 映射记录每个值对应的索引,将的可能取值压缩到范围
-
状态定义:
- :前个位置形成非递减序列,第个位置取的最小成本
- :前个位置形成非递增序列,第个位置取的最小成本
-
状态转移:
- 非递减序列:当前值需≥前一个位置的可能值,取所有中的最小值
- 非递增序列:通过反转序列转化为非递减问题,当前值需≤前一个位置的可能值
-
初始化与优化:
- 第一个位置的成本为
- 利用前缀最小值优化,避免重复计算
五、示例解析
输入:
7 1 3 2 4 5 3 9
-
离散化后序列:
原始序列去重排序后为,对应索引0~5。 -
动态规划过程:
- 非递减序列最优解:
成本为 - 非递增序列需反转原序列后计算,最终取两者最小值3。
- 非递减序列最优解:
六、复杂度分析
- 时间复杂度:
离散化排序,动态规划 - 空间复杂度:
存储动态规划数组和离散化序列
七、注意事项
-
离散化必要性:
若不离散化,可达,无法直接存储所有可能的值。 -
非递增处理:
代码中通过状态转移逻辑隐式处理非递增,实际也可反转序列后求解非递减问题。 -
前缀优化:
利用前缀最小值,避免重复比较前序状态。
八、优化方向
-
滚动数组优化:
观察到仅依赖,可使用滚动数组将空间复杂度降为。 -
二分答案优化:
对于非递减序列,可结合二分查找确定当前位置的最小成本,进一步降低时间复杂度。 -
中位数性质:
当序列长度固定时,最优可能与原始序列的中位数相关,可用于初始化或剪枝。
- 1
信息
- ID
- 2667
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者