【题目】
小明在旅游的路上看到了一条美丽的河,河上有许多船只,有的船只向左航行,有的船只向右航行。小明希望拍下这一美丽的风景,并且把尽可能多的船只都完整地拍到一张照片中。
小明位于河的边上,并且可以在河边的任意位置进行拍照,照相机的视野恰好为90度角,只能以垂直于河边的方向进行拍照。河上的船只全都可看作是平行于河边的一条线段,跟河边的距离各不相同,有的正在向左移动,有的正在向右移动,但移动速度恰好都是一样的。小明可以等待恰当的时间让尽量多的船只都走进照相机的视野里,你不需要考虑船只之间会互相遮挡视野的情况。
![http://acm.hdu.edu.cn/data/images/C715-1003-1.jpg](http://acm.hdu.edu.cn/data/images/C715-1003-1.jpg)
小明位于河的边上,并且可以在河边的任意位置进行拍照,照相机的视野恰好为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(1≤n≤104),表示船只的数量。
接下来 n行,每行四个整数
x,y,z,d(−106≤x<y≤106,1≤z≤104),表示船只的左端点位置、右端点位置、距离河边的距离,以及航行的方向。 d为 −1表示向左航行, 1表示向右航行。
下面 T组数据,对于每组数据:
第一行是一个数 n(1≤n≤104),表示船只的数量。
接下来 n行,每行四个整数
x,y,z,d(−106≤x<y≤106,1≤z≤104),表示船只的左端点位置、右端点位置、距离河边的距离,以及航行的方向。 d为 −1表示向左航行, 1表示向右航行。
Output
对第 i组数据,输出
Case #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
那么如何求同一垂线交过的线段的数量最多,我们把线段的左端点的值当做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;
}