2016百度之星 hdu 5714 离散化+map+差分数组



链接:戳这里


拍照
Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

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

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


思路:

小船行驶分向左和向右方向,同方向的小船的相对位置是静止的

所以最优答案是:向右的小船与向左的小船相遇然后取相遇最大

显然这个相遇的点只可能在  能看到的向右最多的小船的位置  与  能看到的向左最多的小船的位置 的中间

一开始准备枚举这个位置,发现复杂度一直下不去 

需要快速处理出当前位置左边向右最多的小船以及当前位置右边向左最多的小船

差分数组处理出向右小船和向左小船的前缀和,就是一段区间[l,r]的覆盖,进区间+1,出区间-1

额,由于这个左边有点大,所以用了离散化,只找出现的区间  复杂度NlogN


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int n;
map<int,int> mp;
int x[10010],y[10010],d[10010],s[100100],z;
int L[100100],R[100100];
int main(){
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        mp.clear();
        mst(L,0);
        mst(R,0);
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d%d",&x[i],&y[i],&z,&d[i]);
            x[i]=x[i]+z;
            y[i]=y[i]-z;
            if(x[i]<y[i]) continue;
            mp[x[i]+1]++;
            mp[y[i]]++;
        }
        int cnt=0;
        map<int,int > ::iterator it;
        for(it=mp.begin();it!=mp.end();it++){
            int tmp=it->first;
            s[cnt++]=tmp;
        }
        for(int i=1;i<=n;i++){
            if(x[i]<y[i]) continue;
            int posx=lower_bound(s,s+cnt,x[i]+1)-s;
            /// 找到s中>=X+1的第一个元素的位置
            int posy=lower_bound(s,s+cnt,y[i])-s;
            if(d[i]==1){
                R[posx]--;
                R[posy]++;
            } else {
                L[posx]--;
                L[posy]++;
            }
        }
        int ans=0,num=0;
        for(int i=0;i<cnt;i++){
            if(i==0){
                num=max(num,R[i]);
                ans=max(ans,num+L[i]);
                continue;
            }
            R[i]=R[i-1]+R[i];
            num=max(num,R[i]);
            L[i]=L[i-1]+L[i];
            ans=max(ans,num+L[i]);
        }
        printf("Case #%d:\n%d\n",cas,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值