UVALive-7374-Racing Gems(最长上升子序列O(n*logn))

题目链接:点击打开链接

题目大意:
现有一个长为h(竖直方向),宽为w(水平方向)的跑道,跑道上有一些宝石, 给出每一个宝石的坐标。你可以从起点线的任何一个位置(x,0)出发,出发后在竖直方向上有一个恒定的速度v,水平方向上的速度你可以在任意时刻控制在(-v/r~v/r)之间的任何一个值(给出r的值,不给出v的值),当你到达终点线时,移动结束。求你从起点线出发最多可以获得多少宝石。
解题思路:
一:竖直方向上的速度和水平之比为r,那么当人在某一个点时,我们可以确定人在下一个时刻可以行走的方向。即从所在点引出两条斜率分别为r和-r的射线,两线所夹的区域就是可以走的区域,我们将每个点后面能走的区域标出来。
(上个图:)

二:由图可知当某个点B在A所能走的范围之内,也就是在由A点引出的两射线之内时,AB可以都得到,对于图二,C点不在B的范围之内,所以从B不能到C,同理C不能到D,显然图二中的最优解是A->B->-D,对比一下图一,我们可以想到最优情况情况就是找到一些最多的凹槽,并且满足后面的一个凹槽可以包含前面的一个凹槽。

三:可以想到对于每一个点,都去判断一下它前面的点,然后转移一下,复杂度O(n*n),TLE。再仔细想想,所有的射线斜率相等,要一个点(B)被另外一个点(A)完全包含的话,只需要从B出发的射线与两边界的交点都在A出发的射线的交点之上,如果我们求出来了每一个点对应的两个交点,并按照左边的交点从小到大排序,那么我们已经满足了一边上的交点满足后一个点在前一个点之上,我们只需要去找右边交点中的最长连续不降子序列的长度就好了。

四:i)对于排序,如图三,左端点相等时,右端点小的应该优先(看图很好好理解)。

       ii)应该求最长不降子序列,如图四,右端点相等时,两个是可以同时得到的。

       iii)连续最长不降子序列O(n*logn);


代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e5+10;
const LL INF=1e18;
LL longest[maxn];
struct node{
    LL l,r;
}pp[maxn];
bool cmp(node n1,node n2){
    if(n1.l!=n2.l)return n1.l<n2.l;
    return n1.r<n2.r;
}
int main(){
    freopen("in.txt","r",stdin);
    LL n,r,w,h,x,y;
    scanf("%I64d%I64d%I64d%I64d",&n,&r,&w,&h);
    for(int i=0;i<n;i++){
        scanf("%I64d%I64d",&x,&y);
        pp[i].l=x*r+y;
        pp[i].r=(w-x)*r+y;
    }
    sort(pp,pp+n,cmp);
    for(int i=0;i<=n;i++)longest[i]=INF;
    int ans=-1;
    for(int i=0;i<n;i++){
        int id=upper_bound(longest,longest+n,pp[i].r)-longest;//二分查找大于等于该右端的值。
        longest[id]=pp[i].r;
        ans=max(ans,id);
    }
    printf("%d\n",ans+1);
    return 0;
}

其实是看了题解才会的 尴尬 ,当时图画出来了,可是后面的没想到啊。并且以前写的都是n*n地去求最长上升子序列,所以即使想到了貌似也解决不了...,不过O(n*logn)的写法也还挺好写的,毕竟二分不要自己写了。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值