UVALive 7374 Racing Gems - dp,最長上升子序列

題意:賽車從x軸出發往前走,豎直方向速度爲v,水平速度要在-v/r到v/r之間,給出n個鑽石的座標,問賽車最多能拿到多少顆鑽石。

在打組隊賽的時候,我就想到了動態規劃加線段樹優化或者是最長上升子序列的nlog(n)算法,但是都沒有想到具體該怎麼處理,之後證實這兩種方法都能實現,不過由於線段樹還是比較麻煩,所以只實現了最長上升子序列的方法。

這是一個很巧妙的處理,對於每一個鑽石的座標,都能根據水平速度與豎直速度的關係映射到x軸上的一個區間上,對應的y越大,區間長度就越長。對於兩個區間,如果區間a的起點大於等於區間b的起點,而且區間a的終點小於等於b的終點,那麼就可以先拿a點的鑽石,之後去拿b點的鑽石,如果a的起點小於b的起點的話,無論終點怎樣都不可能先拿a再拿b,於是問題就變成了對於n個區間,按照區間的起點降序排序,然後找終點的最長不下降子序列。數據量比較大,但是最長上升子序列有nlog(n)的算法,我抄的模板,也並不是很懂。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
typedef long long ll;
struct node {
    ll b, e;
}id[MAXN];
bool cmp(node a, node b) {
    if(a.b != b.b)
        return a.b > b.b;
    return a.e < b.e;
}
ll dp[MAXN];
int Search(ll num, int low, int high) {
    int mid;
    while(low <= high) {
        mid = (low + high) >> 1;
        if(num >= dp[mid]) low = mid + 1;
        else high = mid  - 1;
    }
    return low;
}
int DDPP(int n) {
    int i, len = 1, pos;
    dp[1] = id[1].e;
    for(i = 2; i <= n; i++) {
        if(id[i].e >= dp[len]) {
            len = len + 1;
            dp[len] = id[i].e;
        }
        else {
            pos = Search(id[i].e, 1, len);
            dp[pos] = id[i].e;
        }
    }
    return len;
}
int main() {
    int i, n, r, w, h, x, y;
    while(~scanf("%d%d%d%d", &n, &r, &w, &h)) {
        for(i = 1; i <= n; i++) {
            scanf("%d%d", &x, &y);
            id[i].b = (ll)x * r - y;
            id[i].e = (ll)x * r + y;
        }
        sort(id + 1, id + n + 1, cmp);
        printf("%d\n", DDPP(n));
    }
    return 0;
}


發佈了67 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章