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

来源:互联网 发布:网络安全法逐条解读 编辑:程序博客网 时间:2024/06/08 02:19

题目链接:点击打开链接

题目大意:
现有一个长为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 longusing 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 0
原创粉丝点击