Lyft Level 5 Challenge 2018

https://codeforces.com/contest/1075/problem/C

题意

一个宽为1e9*1e9的矩阵中的左下角,放置一个车(车可以移动到同一行或同一列),放置一些墙,竖的占据一列,横的有一的长度,问车从最下角走到第1e9行最少拆多少面墙?

思路

  • 看了看数据范围以为是一道离散化的题,但是发现车可以往左走
  • 然后再明确了一下题意,墙是永久拆去的,反应到可以优先拆竖着的墙,然后假如剩下横着的墙比竖着的墙少的话,可以直接拆横着的墙
  • 写之前看了一下题意,说横着的墙不会有交点,然后大致确立了贪心策略:

将横着的墙按高度排序,然后一层一层向上爬,更新最右点,假如最右点>p[i].x2,然后就可以向上爬,假如最右点<=p[i].x2,看剩下横着的边多还是竖着的边多,决定是否要更新最右点

  • 但是上述思路是错的,因为剩下的横边其实有的不一定要拆

题解

  • 首先需要明确两个题意,这对解这道题非常重要
    • 横着的边不会有交点,这一点非常重要,因为根据车的性质,假如横着的边有空隙,假设没有竖边,他就一定可以向上走,所以只需要判每条边的左端点是否1,1的边才需要记录,因为车上不去,这样所有的横边就变成了从1开始的边
    • 墙是永久拆除的,这样竖着的边就等于一个上界,上界越大,意味着要拆的竖边越多,意味着能通过的横边越多
    • 然后就可以枚举竖边(上界),然后找到横边大于上界的点,更新答案(这就是双指针)
#include<bits/stdc++.h>
#define pb push_back
#define M 1e9
using namespace std;
int n,m,i,ans,j,Y,x1,x2;
vector<int>y,x;

int main(){
    cin>>n>>m;
    for(i=0;i<n;i++){scanf("%d",&Y);y.pb(Y);}
    y.pb(M);
    for(i=0;i<m;i++){
        scanf("%d%d%d",&x1,&x2,&Y);
        if(x1==1)x.pb(x2);
    }
    sort(x.begin(),x.end());
    sort(y.begin(),y.end());
    ans=M;
    for(i=0,j=0;i<=n;i++){
        while(j<x.size()&&x[j]<y[i])j++;
        ans=min(ans,(int)(i+x.size()-j));
    }
    cout<<ans;
}
原文地址:https://www.cnblogs.com/VIrtu0s0/p/9948991.html