1 条题解
-
0
题目理解
给定 条消息,每条消息有两个参数 和 。
$$\sum_{i=1}^k a_{p_i} + \sum_{i=1}^{k-1} |b_{p_i} - b_{p_{i+1}}| $$
阅读一个消息集 的代价为:其中消息顺序可以任意排列。用户愿意花费的时间上限为 ,要求找出最大的 使得存在一个大小为 的消息集,其阅读代价 。
关键转化
对于任意选定的消息集合 ,最优的排列顺序是按 值升序(或降序)排列。
$$\sum_{i \in S} a_i \;+\; \bigl( \max_{i \in S} b_i - \min_{i \in S} b_i \bigr) $$
因为排序后,相邻 的绝对值差之和恰好等于 (中间项正负抵消)。
此时总代价为:因此问题转化为:选择一组消息,使得 之和 + ( 的最大值减最小值) ,并最大化消息数量。
算法思路
-
按 排序
将所有消息按 从小到大排序,记排序后的序列为 。 -
枚举左端点 (最小值位置)
对于每个左端点 ,我们考虑所有右端点 ,此时 的范围为 ,代价中的 部分为 。 -
在区间 内选最优子集
固定 范围后,为了最大化消息数量,应该优先选择 值最小的那些消息。
因此维护一个多重集合(multiset)存储当前区间内所有消息的 值,并维护总和cur。 -
贪心剔除
当cur + (b_r - b_l) > l时,说明当前选择的所有消息代价超限。此时我们删除当前集合中 值最大的一个消息(因为去掉大的 能最有效地降低总和,同时只减少一个数量)。重复此操作直到条件满足。 -
更新答案
每次满足条件后,当前集合的大小即为在区间 内能选出的最大消息数量。用ans记录最大值。 -
遍历所有
时间复杂度 ,由于 且 ,完全可行。
代码详解
#include <bits/stdc++.h> using namespace std; signed main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n, L; cin >> n >> L; vector<pair<int, int>> v(n); // (b, a) for (int i = 0; i < n; i++) { cin >> v[i].second >> v[i].first; // 先读 a,再读 b,存入时交换 } sort(v.begin(), v.end()); // 按 b 升序排序 int ans = 0; for (int l = 0; l < n; l++) { multiset<int> s; // 存储当前区间内的 a 值 int cur = 0; // 当前 a 之和 for (int r = l; r < n; r++) { s.insert(v[r].second); cur += v[r].second; // 当总代价超过 L 时,移除当前集合中最大的 a while (!s.empty() && v[r].first - v[l].first + cur > L) { int max_val = *s.rbegin(); // 最大值 cur -= max_val; auto it = s.find(max_val); // 找到该值的一个迭代器 if (it != s.end()) s.erase(it); } ans = max(ans, (int)s.size()); } } cout << ans << "\n"; } return 0; }注意事项
- 排序时
pair的first是 ,second是 ,这样sort默认按 升序。 - 使用
multiset是因为可能存在相同的 值,需要保留多个。 - 删除时使用
find再erase单个元素(C++11 兼容),而非 C++17 的extract。 - 外层循环枚举左端点,内层枚举右端点,每次内层循环中
while删除操作的总次数是 ,因为每个元素最多被插入和删除一次。
正确性证明
- 最优顺序性质:对于任意选定集合,按 排序后代价最小,因此只需考虑排序后的序列。
- 固定 范围:若最小值在 ,最大值在 ,则 部分代价固定为 。此时问题简化为从 中选若干消息,使 尽可能小,从而容纳更多消息。贪心选取最小的 是最优的。
- 贪心剔除:当总和超限时,移除当前最大的 是局部最优决策,因为它最大化降低总和的同时只损失一个消息,最终得到的集合一定是该区间内所有可能子集中大小最大的(经典贪心:保留最小 个 使得总和最小)。
- 遍历所有区间:枚举所有可能的 对,覆盖了所有选择方案,因此能求得全局最优解。
复杂度分析
- 排序:
- 双重循环:外层 次,内层平均 次,每次内层操作(插入、删除)为 ,总复杂度 。
- 由于 ,最坏情况下 ,,乘上 ,总操作约 ,在 3 秒内可接受。
-
- 1
信息
- ID
- 6467
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者