【题目】

小明在旅游的路上看到了一条美丽的河,河上有许多船只,有的船只向左航行,有的船只向右航行。小明希望拍下这一美丽的风景,并且把尽可能多的船只都完整地拍到一张照片中。

小明位于河的边上,并且可以在河边的任意位置进行拍照,照相机的视野恰好为90度角,只能以垂直于河边的方向进行拍照。河上的船只全都可看作是平行于河边的一条线段,跟河边的距离各不相同,有的正在向左移动,有的正在向右移动,但移动速度恰好都是一样的。小明可以等待恰当的时间让尽量多的船只都走进照相机的视野里,你不需要考虑船只之间会互相遮挡视野的情况。

![http://acm.hdu.edu.cn/data/images/C715-1003-1.jpg](http://acm.hdu.edu.cn/data/images/C715-1003-1.jpg)
 

Input
第一行为 T,表示输入数据组数。

下面 T组数据,对于每组数据:

第一行是一个数 n(1n104),表示船只的数量。

接下来 n行,每行四个整数
x,y,z,d(106x<y106,1z104),表示船只的左端点位置、右端点位置、距离河边的距离,以及航行的方向。 d 1表示向左航行, 1表示向右航行。
 

Output
对第 i组数据,输出

Case #i:

然后输出一行,仅包含一个整数,表示最多可以拍到多少完整的船只。
 

Sample Input
3 2 1 3 1 1 2 4 1 -1 2 1 3 1 -1 2 4 1 1 1 1 4 1 1
 

Sample Output
Case #1: 2 Case #2: 1 Case #3: 0
【解题思路】对于船[x,y,z],当x+z>=y-z的时候,可以在[y-z,x+z]这些位置观测到它,那么我们可以处理出来n条线段,我们要求同一垂线交过的线段的数量最多,由于船是可以移动的,那么我们可以固定同一方向的船不动,假设初始在x位置观测往右的船,在y位置观测到往左的船,只要x<=y,那么经过一段时间我们就可以在同一角度观察到这些船。

那么如何求同一垂线交过的线段的数量最多,我们把线段的左端点的值当做1,右端点当成-1,然后就是一个累计的过程,我们要先预处理出每一个端点向左走的船的最大值,最后O(n)扫一遍即可。总复杂度nlogn。

【PS】啊啊啊啊啊啊,百度之星复赛爆0,没脸见人【掩面哭泣】其实就这个题就是个***题啊。

【AC代码】

#include <bits/stdc++.h>
using namespace std;
const int maxn=20005;
int n;
struct node{
    int x,val,d;//x代表端点值,val代表左端点还是右端点,d代表线段的方向
    node(int x=0,int val=0,int d=0):x(x),val(val),d(d){}
    bool operator<(const node &a)const
    {
        if(x!=a.x) return x<a.x;
        if(val!=a.val) return val>a.val;
        return d>a.d;
    }
}boat[maxn];
int ans[maxn];//每一个端点向左走的船的最大值
int main()
{
    int T,cas=1,x,y,z,d;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        int cnt=0;
        for(int i=0; i<n; i++)
        {
            scanf("%d%d%d%d",&x,&y,&z,&d);
            int l=y-z,r=x+z;
            if(l<=r)
            {
                boat[cnt++]=node(l,1,d);
                boat[cnt++]=node(r,-1,d);
            }
        }
        sort(boat,boat+cnt);
        //预处理每一个端点向左走的船的最大值
        memset(ans,0,sizeof(ans));
        int now=0;
        for(int i=cnt-1; i>=0; i--)
        {
//            if(boat[i].d<0)//向左走的船
//            {
//                if(boat[i].val==-1) now++;
//                ans[i]=max(ans[i+1],now);
//                if(boat[i].val==1)  now--;
//                //ans[i]=max(ans[i+1],now);
//            }
              if(boat[i].d<0&&boat[i].val==-1) now++;
              ans[i]=max(now,ans[i+1]);
              if(boat[i].d<0&&boat[i].val==1) now--;
              ans[i]=max(now,ans[i+1]);
        }
        //for(int i=0; i<cnt; i++) cout<<ans[i]<<" ";cout<<endl;
        //O(n)维护答案
        now=0;
        int maxans=0;
        for(int i=0; i<cnt; i++)
        {
            if(boat[i].d>0)//向右走的船
            {
                if(boat[i].val==1)  now++;
                maxans=max(maxans,ans[i]+now);
                if(boat[i].val==-1) now--;
                maxans=max(maxans,ans[i]+now);
            }
        }
//        printf("%d %d\n",cas++,maxans);
        printf("Case #%d:\n",cas++);
        printf("%d\n",maxans);
    }
    return 0;
}