1 条题解
-
0
F1. 完成所有项目(简单版本)
问题重述
Polycarp 当前评分为 。有 个项目,第 个项目需要评分至少 才能开始,完成后评分变化为 (可正可负)。评分在任何时候不能低于 。
问:是否存在一种顺序,使得所有项目都能完成?- ,
- ,
核心思路
将项目分为两类:
- 加分项目:
- 减分项目:
第一步:处理加分项目
对于 的项目,显然应该按照 从小到大排序(先做要求低的,再做要求高的)。
依次检查当前评分是否 ,若是则完成并更新 ;否则直接输出"NO"。第二步:处理减分项目
对于 的项目,情况更复杂。
关键观察:完成一个减分项目后评分会下降,所以需要合理安排顺序。
减分项目的贪心策略
引理
将所有减分项目按 从大到小排序,然后依次尝试完成,是最优的。
证明思路(交换论证)
考虑两个相邻的减分项目 和 ()。
假设当前评分为 ,先做 再做 可行的条件是:先做 再做 可行的条件是:
我们希望选择约束更弱的顺序。比较两个条件中的关键项:
- 先 后 要求
- 先 后 要求
注意到 ,,所以只需比较 和 。
计算:
$$(a_j - b_i) < (a_i - b_j) \iff a_j + b_j < a_i + b_i $$因此,当 时,先做 再 的条件更弱(更容易满足)。
所以应该按 从大到小排序。
处理边界条件
对于减分项目,还有一个细节:
为了保证完成项目后评分非负,在尝试完成前需要额外检查:因为如果 ,则完成后的评分 。
所以实际操作中,可将 更新为 ,再按 排序。
算法步骤
- 读入
- 将项目分为两组:
pos:,按 升序排序neg:,按 降序排序(或按 升序?需注意)
- 处理
pos组:依次判断 ,更新 - 处理
neg组:依次判断 且 ,更新 - 若所有项目都完成,输出
"YES",否则"NO"
时间复杂度
排序 ,遍历 ,总体 。
示例解析
示例 1
3 4 4 6 10 -2 8 -1- 加分项目:
(4,6),按 排序后唯一, → - 减分项目:
(10,-2),(8,-1)
计算 :,,按降序:先(10,-2)后(8,-1)
当前 :完成(10,-2)→
完成(8,-1)→
全部完成 →"YES"
标程代码(C++)
#include <bits/stdc++.h> using namespace std; int main() { int n, r; cin >> n >> r; vector<pair<int, int>> pos, neg; for (int i = 0; i < n; ++i) { int a, b; cin >> a >> b; if (b >= 0) { pos.push_back({a, b}); } else { neg.push_back({a, b}); } } // 处理加分项目 sort(pos.begin(), pos.end()); for (auto &p : pos) { if (r < p.first) { cout << "NO" << endl; return 0; } r += p.second; } // 处理减分项目:按 a+b 降序排序 sort(neg.begin(), neg.end(), [](pair<int, int> x, pair<int, int> y) { return x.first + x.second > y.first + y.second; }); for (auto &p : neg) { if (r < p.first) { cout << "NO" << endl; return 0; } r += p.second; if (r < 0) { cout << "NO" << endl; return 0; } } cout << "YES" << endl; return 0; }
易错点
- 减分项目的排序依据是 降序,不是 升序
- 完成减分项目后要检查 是否
- 可能小于 ,此时实际要求是 (但标程中直接用 判断,因为 已经保证了这一点?需要确认)
- 1
信息
- ID
- 6422
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者