牛客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≤L≤R≤109,1≤N≤109,1≤M≤105
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; }