2 条题解
-
2
思路
省流:这个题是个贪心。
不用说也能看出来,但我唐完了第一眼看成dp了把题目分成两类:
1.,此时打这个关卡是有收益的,为了让起始精力最小,我们很容易想到按 (就是代价)从小到大排序。
2.,此时打关卡是亏的,我们自然能联想到按回报排序,如果回报相同,我们按代价排序,这样我们就算亏,也能为下一次存下一些精力。此时还有更为严谨的邻项交换法,当前精力 ,先打 再打 就要满足 ,移项得 反之就是 ,移项得 ,因为 是定值,所以 越小对 的要求就更小,可知按 排序。
于是我们可以把数组分成两个分别排序,先处理第一类,在处理第二类,因为第一类先做可以盈利,尽可能使精力需要的最小。
然后我们可以二分也可以模拟,当然我觉得模拟更简洁,每次记录当前精力 ,如果不足以通过就给 加上差距(即需要补的),同时把 更新成当前的 (尽可能少补)。 初始时 。
代码
#include <bits/stdc++.h> using namespace std; using LL = long long; const int MAXN = 1e5 + 10; int n; LL maxv, sum, ans, H; vector<int> p1, p2; struct Node { LL A, B; } p[MAXN]; bool cmp1(int a, int b) { return p[a].A < p[b].A; } // 第一类 bool cmp2(int a, int b) { return p[a].B != p[b].B ? p[a].B > p[b].B : p[a].A < p[b].A; } // 第二类 int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cin >> n; for (int i = 1; i <= n; ++i) { cin >> p[i].A >> p[i].B; maxv = max(maxv, p[i].A); if (p[i].A <= p[i].B) p1.push_back(i); else p2.push_back(i); } sort(p1.begin(), p1.end(), cmp1); sort(p2.begin(), p2.end(), cmp2); for (int k : p1) { if (H < p[k].A) ans += (p[k].A - H), H = p[k].A; H -= p[k].A; H += p[k].B; } // 先处理的 for (int k : p2) { if (H < p[k].A) ans += (p[k].A - H), H = p[k].A; H -= p[k].A; H += p[k].B; } // 后处理的 cout << ans; return 0; }
信息
- ID
- 2789
- 时间
- 300ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 26
- 已通过
- 5
- 上传者