牛客小白月赛12——A.华华听月月唱歌

版权声明:本文为博主原创,未经博主允许不得转载 https://blog.csdn.net/Sherry_Yue/article/details/88539942

华华听月月唱歌

点击做题网站链接

题目描述
月月唱歌超级好听的说!华华听说月月在某个网站发布了自己唱的歌曲,于是把完整的歌曲下载到了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

备注:
1 L R 1 0 9 , 1 N 1 0 9 , 1 M 1 0 5 1≤L≤R≤10^9,1≤N≤10^9,1≤M≤10^5

解题思路:

考虑贪心,将所有区间按照左端点排序,从左往右遍历。用一个变量维护我们当前最远可以够到的右端点,然后枚举左端点不超过右端点+1的所有区间,选择右端点最靠右的一个即可。时间复杂度O(NlogN)。

解题代码:

#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 1e5+5;
struct node
{
    int l, r;
}a[MAX];//存储M个片段区间

bool cmp(node a, node b){return a.l<b.l;}

int main()
{
    int N, M;//歌曲的原长和片段的个数
    int ans = 0;//计数最少区间
    int MaxDis = 0;//标记最远可以够到的右端点
    int i = 1;//遍历1到M个片段
    while( cin >> N >> M )
    {
        for(int i=1;i<=M;++i)
            cin >> a[i].l >> a[i].r;
        sort(a+1,a+M+1,cmp);//第一个元素存储在a[1]
        
        while( MaxDis<N )//当最远可以够到的右端点小于歌曲的原长时
        {
            //遍历区间左端点不超过之前区间最远右端点+1的所有区间,
            //选择右端点最靠右的一个,并用temp记录其值
            int temp = 0;
            while( a[i].l<=MaxDis+1 && i<=M )
            {
                temp = max(a[i].r,temp);
                ++i;
            }
            if( temp>=MaxDis )//当temp>=之前标记的最远可以够到的右端点时
            {
                MaxDis = temp;//更新最远可以够到的右端点的值
                ++ans;//计数+1
            }
            else//否则代表区间中间断开了,即区间的并集不全部包含1到N
            {
                ans = -1;
                break;
            }
        }
    }
    cout << ans << endl;
}

猜你喜欢

转载自blog.csdn.net/Sherry_Yue/article/details/88539942