1. 程式人生 > >[洛谷P2107] 小Z的AK計劃

[洛谷P2107] 小Z的AK計劃

pre top names 然而 yqi 解題思路 情況 show getc

題目類型:貪心,堆

傳送門:>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;
}

[洛谷P2107] 小Z的AK計劃