题解:AtCoder AT_awc0081_d Organizing the Bookshelf
【题目来源】
AtCoder:D - Organizing the Bookshelf
【题目描述】
Takahashi has \(N\) books arranged in a row from left to right on his bookshelf. The \(i\)-th book from the left has \(A_i\) pages, and to remove this book from the bookshelf and have it taken by a used bookstore, Takahashi must pay a handling fee of \(C_i\). No fee is charged for books that remain on the bookshelf.
To improve the appearance of his bookshelf, Takahashi wants to remove some books so that the page counts of the remaining books are strictly monotonically increasing from left to right. That is, when looking at the remaining books from left to right, for any two adjacent books, the page count of the left book must be strictly less than the page count of the right book. Note that since books are only removed and not rearranged, the relative order of the remaining books is the same as the original order.
The number of books removed may be any number from \(0\) to \(N\), inclusive. The strictly monotonically increasing condition is considered satisfied when \(0\) or \(1\) books remain.
Find the minimum total handling fee of the removed books when choosing which books to remove so that the page counts of the remaining books are strictly monotonically increasing from left to right.
高桥的书架上从左到右排列着 \(N\) 本书。从左数第 \(i\) 本书有 \(A_i\) 页,要将这本书从书架上取下并交给二手书店,高桥需要支付 \(C_i\) 的手续费。留在书架上的书不收取任何费用。
为了改善书架的外观,高桥想移除一些书,使得剩下书籍的页数从左到右是严格单调递增的。也就是说,从左到右看剩下的书籍时,任意两本相邻的书,左侧书的页数必须严格小于右侧书的页数。注意,由于只移除书籍而不重新排列,剩下书籍的相对顺序与原始顺序相同。
移除的书籍数量可以是 \(0\) 到 \(N\) 之间的任意数量。当剩下 \(0\) 本或 \(1\) 本书时,严格单调递增的条件被认为满足。
当选择移除哪些书使得剩下书籍的页数从左到右严格单调递增时,求移除书籍的最小总手续费。
【输入】
\(N\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
\(C_1\) \(C_2\) \(\ldots\) \(C_N\)
- The first line contains an integer \(N\) representing the number of books.
- The second line contains \(N\) integers \(A_1, A_2, \ldots, A_N\) separated by spaces, representing the page counts of each book. Here, \(A_i\) is the page count of the \(i\)-th book from the left.
- The third line contains \(N\) integers \(C_1, C_2, \ldots, C_N\) separated by spaces, representing the handling fees for removing each book. Here, \(C_i\) is the handling fee Takahashi must pay to remove the \(i\)-th book from the left.
【输出】
Print in one line the minimum total handling fee of the removed books when choosing which books to remove so that the page counts of the remaining books are strictly monotonically increasing.
【输入样例】
5
3 1 4 1 5
10 20 30 40 50
【输出样例】
50
【核心思想】
-
问题分析:给定 \(N\) 本书,每本书有页数 \(A_i\) 和移除费用 \(C_i\)。需要移除若干本书,使得剩余书籍的页数严格单调递增。求移除书籍的最小总费用。注意到总费用 \(\sum C_i\) 固定,最小化移除费用等价于最大化保留书籍的费用和,而保留的书籍必须构成严格递增子序列。因此这是一个带权最长递增子序列(Weighted LIS) 问题。
-
算法选择:
- 线性 DP(带权 LIS):
f[i]表示以第 \(i\) 本书结尾的严格递增子序列的最大保留费用和 - 转化思想:答案 = 总费用 - 最大保留费用和,将"最小移除费用"转化为"最大保留价值"
- 线性 DP(带权 LIS):
-
关键步骤:
- 读取输入:\(N\)、页数数组 \(A[1..N]\)、费用数组 \(C[1..N]\)
- 预处理总费用:
sum = \sum_{i=1}^{N} C_i - DP 初始化:
f[i] = C_i(每本书单独作为子序列的结尾) - 状态转移:对于每个 \(i\) 从 \(1\) 到 \(N\):
- 枚举 \(j\) 从 \(1\) 到 \(i-1\)
- 若 \(A_j < A_i\)(满足严格递增):
f[i] = \max(f[i], f[j] + C_i)
- 统计最大保留费用:
res = \max_{i=1}^{N} f[i] - 输出答案:
sum - res
-
时间/空间复杂度:
- 时间复杂度:\(O(N^2)\),双重循环枚举所有 \((j, i)\) 对
- 空间复杂度:\(O(N)\),一维 DP 数组
-
带权 LIS 的核心思想:
- 转化视角:当问题要求"删除最小代价"且总代价固定时,等价于求"保留最大代价",后者是经典的 DP 模型
- 状态设计:
f[i]记录以 \(i\) 结尾的最优子序列权值和,只依赖前面更小的元素,具有最优子结构 - 严格递增条件:转移时要求 \(A_j < A_i\)(而非 \(\leq\)),确保剩余序列严格单调递增
- \(N \leq 5000\) 时 \(O(N^2)\) 可接受;若 \(N\) 更大,可结合离散化 + 树状数组/线段树优化至 \(O(N \log N)\)
- 适用于带权值的子序列选择、最小删除代价、最大保留价值类问题
【算法标签】
线性DP-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5005;
int n, sum, res; // n: 数组长度,sum: 总和,res: 最长递增子序列的最大和
int a[N], c[N]; // a: 数组a,c: 代价数组
int f[N]; // 动态规划数组
signed main()
{
cin >> n; // 输入数组长度
for (int i = 1; i <= n; i++) // 输入数组a
cin >> a[i];
for (int i = 1; i <= n; i++) // 输入代价数组c
{
cin >> c[i];
sum += c[i]; // 计算总代价
}
for (int i = 1; i <= n; i++) // 遍历每个位置
{
// 不选前面的
f[i] = c[i]; // 初始化为只选当前元素
// 选前面的
for (int j = 1; j < i; j++) // 遍历前面的位置
{
if (a[j] < a[i]) // 如果满足递增条件
f[i] = max(f[i], f[j] + c[i]); // 状态转移
}
res = max(res, f[i]); // 更新最大值
}
cout << sum - res << endl; // 输出最小代价
return 0;
}
【运行结果】
5
3 1 4 1 5
10 20 30 40 50
50
浙公网安备 33010602011771号