GYM 100820 G.Racing Gems(LIS)

来源:互联网 发布:js 实现数据实时更新 编辑:程序博客网 时间:2024/06/20 00:03

Description
在[0,w]x[0,h]的区域内赛车,初始时可以任意选取x轴上[0,w]内一点作为起点,只要到达y=h在[0,w]范围内任一点即为到达终点,赛车的垂直车速为v,水平车速可以在-v/r~v/r内任意变化,给出该区域内n个钻石的坐标,问在赛车过程中最多可以拿到多少钻石
Input
第一行输入四个整数n,r,w,h,之后n行每行两个整数表示一颗钻石的坐标(1<=n<=1e5,1<=r<=10,1<=w,h<=1e9,0<=x[i]<=w,0<=y[i]<=h)
Output
输出最多可以拿到的钻石数量
Sample Input
5 1 10 10
8 8
5 1
4 6
4 7
7 9
Sample Output
3
Solution
当赛车拿到一个钻石后,其下一个可以拿到的钻石所处范围必须要在以第i个点往上的斜率分别为-r和r的射线之间,设由第i个点发出的两条射线与左右边界交点的纵坐标分别为a[i]和b[i],那么拿到钻石i后可以拿到钻石j等价于钻石j在由第i个点发出的这两条射线之间,进一步等价于a[j]>=a[i],b[j]>=b[i],所以求出每个钻石发出射线与左右两边界的交点(a[i],b[i]),问题变成求这个二维序列的最长上升子序列长度,先按第一维升序排,对第二维求一个最长上升子序列即可
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;#define INF 1e12#define maxn 111111int n,r,w,h;struct node{    ll a,b;    bool operator<(const node&c)const    {        if(a!=c.a)return a<c.a;        return b<c.b;    }}p[maxn];ll a[maxn],dp[maxn];int LIS(ll a[])//求序列a的(非严格)最长上升子序列 {    for(int i=1;i<n;i++)dp[i]=INF;    dp[0]=a[0];    int len=1;    for(int i=1;i<n;i++)    {        if(a[i]>=dp[len-1])dp[len++]=a[i];        else dp[upper_bound(dp,dp+n,a[i])-dp]=a[i];    }    return len;}int main(){    while(~scanf("%d%d%d%d",&n,&r,&w,&h))    {        for(int i=0;i<n;i++)        {            ll x,y;            scanf("%I64d%I64d",&x,&y);            p[i].a=1ll*r*x+y,p[i].b=1ll*r*(w-x)+y;        }        sort(p,p+n);        for(int i=0;i<n;i++)a[i]=p[i].b;        printf("%d\n",LIS(a));    }    return 0;}
原创粉丝点击