P2107 小 Z 的 AK 计划 贪心
P2107 小 Z 的 AK 计划
题目大意
机房一条街有 \(n\) 个机房,第 \(i\) 个机房的坐标为 \(x_i\),小 Z 的家坐标为 \(0\)。小 Z 在街上移动的速度为 \(1\),即从 \(x_1\) 到 \(x_2\) 所耗费的时间为 \(|x_1 - x_2|\)。
小 Z 到达第 \(i\) 个机房后,可以花 \(t_i\) 的时间想题,然后瞬间 AK;当然,也可以过机房而不入。
小 Z 现在只有 \(m\) 个单位时间。现在他想知道自己最多能在多少个机房 AK,希望你帮帮他。
说明/提示
对于 \(30\%\) 的数据,\(n \leq 20\)。
对于 \(60\%\) 的数据,\(n \leq 1000\)。
对于 \(100\%\) 的数据,\(1 \leq n \leq 10^5\),\(0 \leq m,x_i \leq 10^{18}\),\(0 \leq t_i \leq 10^9\)。
思路
当 \(n \le 1000\) 时,我们显然是可以通过动态规划做的。但是这题最大的 \(n\) 达到了\(10^5\),DP 时间复杂度为 \(O(nm)\),超飞了。于是我们想可不可以贪心求解。
我们先一直往前走,走到下一个机房,看在还剩下的时间内能不能AK,若是可以AK,就放进priority_queue里面;若不可以AK,那么试试将前面选择AK的耗时最大的一或多个去掉,再看看是否AK,重复这么做,每次统计可以AK的机房的最大值,就没了。
那么正确性怎么证明呢?我只能说显然。
/*
@ Author: Eric / Sky__White
@ Filename: P2107.cpp
@ Date: 10/07/2026
@ Email: acwing@foxmail.com / 17802535158@163.com
*/
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <queue>
namespace std {
class Read {
public:
template<typename T>
inline Read operator >> (T & x) {
T sum = 0, opt = 1;
char ch = getchar();
while(!isdigit(ch)) opt = (ch == '-') ? -1 : 1, ch = getchar();
while( isdigit(ch)) sum = (sum << 1) + (sum << 3) + (ch ^ 48), ch = getchar();
x = sum * opt;
return *this;
}
};
}
#define int long long
#define all(a) a.begin(), a.end()
using namespace std; Read fin;
signed main() {
int n, m; cin >> n >> m;
vector<pair<int, int> > arr(n + 1);
for (int i = 1; i <= n; i ++ ) {
fin >> arr[i].first >> arr[i].second;
}
sort(1 + all(arr));
int dis = 0, sum = 0, res = 0, ans = 0;
priority_queue<int> q;
for (int i = 1; i <= n; i ++ ) {
dis = arr[i].first; sum += arr[i].second; ans ++ ;
q.push(arr[i].second);
while (q.size() and sum + dis > m) {
sum -= q.top(); q.pop();
ans -- ;
}
cout << ans << endl;
res = max(res, ans);
}
cout << res << endl;
}

浙公网安备 33010602011771号