UVALive 7374 Racing Gems (最长上升子序列--二分法)

大体题意:

你在一个二维坐标轴上运动,每一行都有钻石,你竖直运动速度固定,是V,水平速度  是-V/R ~ V/R不等!你可以随时调整速度!刚开始你在Y轴0~w任意一个位置,求出你所吃的钻石的最大数目?

思路:

题解很巧妙,既然你可以随时调整速度,你为了吃到更多,只看最大速度就行了!

我们可以在每一个钻石求出一个覆盖范围,什么意思呢,既然水平速度   向左的最大值等于向右的最大值,那么肯定是一个等腰三角形了,只需要求出所有钻石在X轴上所有覆盖范围,求出 有多少个完全覆盖的钻石就是答案!

因此 我们可以给范围左端点进行从大到小排序,相同按照右端点从小到大排序,对右端点求最长上升子序列即可!

有个优化,如果一个钻石坐标是(X,Y)的话,那么覆盖左端点是X - Y/r,,右端点是X + Y/r,有小数存在误差,因此我们可以直接两边乘以r,因为我们只在意相对谁大谁小,并不在意大多少。所有可以乘以r避免小数,但是这样做会爆int,开long long 就好了!!

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
using namespace std;
const int maxn = 100000 + 7;
typedef long long ll;
struct Node{
    ll s,e;
    bool operator < (const Node & rhs) const {
        return s > rhs.s || (s == rhs.s && e < rhs.e);
    }
}p[maxn];
ll lcs[maxn];
int main(){
    int n,r,w,h;
    while(scanf("%d %d %d %d",&n,&r,&w,&h) == 4){
        for (int i = 0; i < n; ++i){
            int x,y;
            scanf("%d %d",&x,&y);
            p[i].s = (ll)r*(ll)x-(ll)y;
            p[i].e = (ll)r*(ll)x+(ll)y;
        }
        sort(p,p+n);
        lcs[0] = p[0].e;
        int cnt = 1;
        for (int i = 1; i < n; ++i){
            if (p[i].e >= lcs[cnt-1]){
                lcs[cnt++] = p[i].e;
            }else {
                int l = 0,r = cnt-1;
                while(l <= r){
                    int mid = l+r>>1;
                    if (lcs[mid] >= p[i].e)r = mid - 1;
                    else l = mid + 1;
                }
                lcs[l] = p[i].e;
            }
        }
        printf("%d\n",cnt);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值