[题解]P2107 小 Z 的 AK 计划
考虑反悔贪心。我们尽可能 AK 所有路过的机房,如果 AK 当前机房后时间不够用,则从所有 AK 过的机房(包括当前)中取耗时最长的删掉,直到时间够用或者没有机房为止。
可以用一个堆来维护耗时最长的机房。总时间 \(O(n\log n)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
struct Nd{int x,t;}a[N];
priority_queue<int> q;
int n,m,t,ans,cur;
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].t;
sort(a+1,a+1+n,[](Nd a,Nd b){return a.x<b.x;});
for(int i=1;i<=n;i++){
t+=a[i].x-a[i-1].x+a[i].t;
q.push(a[i].t);
cur++;
while(!q.empty()&&t>m){
cur--;
t-=q.top();
q.pop();
}
if(t>m) break;
ans=max(ans,cur);
}
cout<<ans<<"\n";
return 0;
}
另一种做法是线段树上二分。AK 机房的时间和走路的时间是两个因素,我们钦定其中一个就很简单了。
我们可以枚举每个 \(x_i\),问题转化为“仅走到 \(x_i\) 最多能 AK 多少机房”,也即“\(m-x_i\) 的时间内能 AK 多少个 \(1\sim i\) 的机房”。
为此我们可以按 \(x\) 为机房排序,枚举到 \(x_i\) 时,将 \(t_1,t_2,\dots t_x\) 扔到线段树的对应位置,线段树上二分即可。
总时间 \(O(n\log n)\)。
浙公网安备 33010602011771号