牛客392A 经典区间覆盖

链接:https://ac.nowcoder.com/acm/contest/392/A
来源:牛客网

题目描述

月月唱歌超级好听的说!华华听说月月在某个网站发布了自己唱的歌曲,于是把完整的歌曲下载到了U盘里。然而华华不小心把U盘摔了一下,里面的文件摔碎了。月月的歌曲可以看成由1到N的正整数依次排列构成的序列,它现在变成了若干个区间,这些区间可能互相重叠。华华想把它修复为完整的歌曲,也就是找到若干个片段,使他们的并集包含1到N(注意,本题中我们只关注整数,见样例1)。但是华华很懒,所以他想选择最少的区间。请你算出华华最少选择多少个区间。因为华华的U盘受损严重,所以有可能做不到,如果做不到请输出-1。

输入描述:

第一行两个正整数N、M,表示歌曲的原长和片段的个数。
接下来M行,每行两个正整数L、R表示第i的片段对应的区间是[L,R]。

输出描述:

如果可以做到,输出最少需要的片段的数量,否则输出-1。
示例1

输入

复制
4 2
1 2
3 4

输出

复制
2
示例2

输入

复制
4 2
1 1
3 4

输出

复制
-1
示例3

输入

复制
10 5
1 1
2 5
3 6
4 9
8 10

输出

复制
4

备注:

1LR109,1N109,1M105


A

区间覆盖的经典题目虽然思路很清楚,但是实现的方式也很重要,不同的实现方式的复杂度和容易出错的程度会有差别。这题中,有的是更新一个当前的最大区间,另一个是寻找下一个待找区间。第二种方式实现起来有不少细节需要注意,例如这两组数据,需要注意因为这两组数据,例如当前位置为6,需要考虑选择出下一个区间,很明显应该从这三个(【6,8】 6,6】 【7,9】)中选择最后面的【7,9】 。所以如果用第二种方式还要加一个while判断寻找合适的区间。花费了将近三小时。
附两组样例
18 5
0 7
2 18
13 30s
17 20
12 21


15 7
7 15
6 8
14 26
0 6
2 6
6 6
12 12


#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cmath>
#include <bitset>
#include <vector>
#include <iomanip>
#include <sstream>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long  ll;
#define mem(A, X) memset(A, X, sizeof A)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i))
#define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i))

ll n,m;
struct qujian{
    ll l,r;
};
qujian a[100005];
bool cmp(qujian a,qujian b){
    if(a.l<b.l) return true;
    else if(a.l==b.l){
        if(a.r>=b.r) return true;

    }
    return false;
}
void solve(){
    fori(i,1,m){
        if(a[i].r>n) a[i].r=n;
        if(a[i].l<1){
            if(a[i].r>0) a[i].l=1;
            else {
                a[i].l=n+10;
                a[i].r=n+10;
            }
        }
    }
    sort(a+1,a+1+m,cmp);
    //fori(i,1,m) cout<<a[i].l<<","<<a[i].r<<"   ";
    //cout<<endl;
    int cnt=0;
    int cur=0;
    bool flag=true;
    int ans=-1;
    if(a[1].l!=1) flag=false;
    else {
        cur=1;
        cnt=1;
        for(int i=2;i<=m;){

            //cout<<"cur: a"<<cur<<" :"<<a[cur].l<<" "<<a[cur].r<<endl;
            //cout<<"i  : a"<<i<<" :"<<a[i].l<<" "<<a[i].r<<endl;

            if(a[i].l>=a[cur].r+2 ) {
                if( a[cur].r<n){
                    flag=false;
                    break;
                }
                i++;
            } else if(a[i].r>=a[cur].r+1){
                bool can_sel=true;
                int nxtpos=i;

                //if(i!=m && a[i+1].l<=a[cur].r+1 && a[i+1].r>a[i].r) continue;
                int t=i+1;
                int tmax=a[i].r;
                while( t<=m &&a[t].l<=a[cur].r+1 ){
                    if(a[t].r>tmax) {
                        nxtpos=t;
                        tmax=a[t].r;
                        can_sel=false;
                    }
                    t++;
                }

                if(can_sel){
                    cur=i;
                    cnt++;
                    //cout<<"sel: "<<a[cur].l<<","<<a[cur].r<<endl;
                    i++;
                }else {
                    i=nxtpos;
                    cur=i;
                    cnt++;
                    //cout<<"sel: "<<a[cur].l<<","<<a[cur].r<<endl;
                    i++;

                }
            } else {
                i++;
            }
        }
        if(a[cur].r<n) flag=false;
    }
    if(flag) ans=cnt;
    cout<<ans<<endl;
}
int main()
{
  ios::sync_with_stdio(false);
  freopen("pai.in","r",stdin);
  //freopen("2wa.out","w",stdout);
  int case_cnt=1;
  while(cin>>n>>m){
      //cout<<"case"<<case_cnt++<<endl;
      fori(i,1,m){
          cin>>a[i].l>>a[i].r;
      }
      solve();
  }

return 0;
}
View Code

 



posted @ 2019-03-13 20:30  TechIsOnlyTool  阅读(287)  评论(0编辑  收藏  举报