HDU 5714 拍照 前缀和

拍照

题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=5714

Description

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

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

https://i-blog.csdnimg.cn/blog_migrate/cdadbb106e3b1904afbdfbc57e6b244a.jpeg

Input

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

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

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

接下来n行,每行四个整数
x,y,z,d(−106≤x<y≤106,1≤z≤104),表示船只的左端点位置、右端点位置、距离河边的距离,以及航行的方向。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

Hint

题意

题解:

分成两个方向去做,在同一个方向的船的相对位置会保持不变,那么我们相当于每条船会给你一个线段

然后你可以得到线段最大重叠数……

单方向做完了之后,你会发现,只要r>l,r是向左走的船坐标,l是向右走的船的坐标

那么肯定在某一时刻,这俩坐标是会重叠的,所以只要记录一个前缀最大值,然后莽一波就好了

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
map<int,int> H;
int l[maxn],r[maxn],x[maxn],y[maxn],z[maxn],d[maxn];
vector<int>V;
int tot,c[maxn],n;
void init()
{
    tot=0;
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    H.clear();V.clear();
}
void solve(int cas)
{
    init();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&x[i],&y[i],&z[i],&d[i]);
        V.push_back(y[i]-z[i]),V.push_back(x[i]+z[i]+1);
    }
    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());
    for(int i=0;i<V.size();i++)
        H[V[i]]=i+1;
    for(int i=1;i<=n;i++)
    {
        if(y[i]-z[i]<=x[i]+z[i])
        {
            int x1=H[y[i]-z[i]],x2=H[x[i]+z[i]+1];
            if(d[i]==1)l[x1]++,l[x2]--;
            else r[x1]++,r[x2]--;
        }
    }
    int Max = 0,Ans = 0;
    for(int i=1;i<=V.size();i++)
    {
        l[i]+=l[i-1],r[i]+=r[i-1];
        Max=max(Max,l[i]);
        Ans=max(Ans,Max+r[i]);
    }
    printf("Case #%d:\n%d\n",cas,Ans);
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
        solve(i);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值