[洛谷P2107] 小Z的AK计划

题目类型:贪心,堆

传送门:>Here<

题意:给出\(N\)个房间,每个房间距离起点的距离为\(x[i]\),每个房间可以选择进去和不进去,如果进去了那么要\(t[i]\)秒后才能出来。问在\(M\)秒内最多能进多少个房间

解题思路

第一眼是一个\(01\)背包,然而枚举当前房间和上一个房间,加上所用时间,复杂度\(O(n^3)\)……

考虑枚举终点,这样所有路上的时间之和就可以确定了。然后就是看在剩余的时间里最多能去几个房间,这个很简单——假设全去,如果超时,那么每次踢出耗时最多的那个房间。每次踢出最大的,用一个大根堆维护即可。复杂度\(O(nlogn)\)

反思

不要认为一道题是\(DP\)就死往\(DP\)里钻……其实可能根本不是\(DP\)而是贪心。贪心和\(DP\)在很多情况下同时适用于一个问题。

不能被题目迷惑……题目所说的距离和进入房间所需要的都是时间,好像混为一谈。实际上要是割裂开来看就异常简单了。

Code

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define int ll
const int MAXN = 100010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
struct Room{
	int x, t;
}a[MAXN];
inline bool operator < (const Room& a, const Room& b){
	return a.t < b.t;
}
int N,M,ans,sum,cnt;
priority_queue <Room> q;
inline bool pos_cmp(const Room& a, const Room& b){
	return a.x < b.x;
}
signed main(){
	N = read(), M = read();
	for(int i = 1; i <= N; ++i){
		a[i].x = read();
		a[i].t = read();
	}
	sort(a+1, a+N+1, pos_cmp);
	for(int i = 1; i <= N; ++i){
		q.push((Room){a[i].x, a[i].t});
		sum += a[i].t + a[i].x - a[i-1].x;
		while(sum > M && q.size()){
			sum -= q.top().t;
			q.pop();
			--cnt;
		}
		++cnt;
		ans = Max(ans, cnt);
	}
	printf("%d", ans);
	return 0;
}
posted @ 2018-10-05 20:19  DennyQi  阅读(305)  评论(0编辑  收藏  举报