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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值