(贪心)2017"百度之星"程序设计大赛 - 初赛(B) 1006 小小粉丝度度熊

新博客地址: vonsdite.cn

2017"百度之星"程序设计大赛 - 初赛(B) 1006 小小粉丝度度熊
hdu 6119

题意

  • 第一行两个整数n,m,表示有n个区间,这n个区间内的天数,度度熊都签到了;m表示m张补签卡。

  • 接下来n行,每行两个整数(l[i],r[i]),表示度度熊从第l[i]天到第r[i]天,都进行了签到操作。

  • 在使用最多m张补签卡的情况下,度度熊最多连续签到多少天呢?

思路

  • 先对所有区间按左侧从小到大排序,左侧相同按右侧从小到大排序
  • 再将重叠区间合并掉
  • 然后用sum数组记录区间之间的间隔和
  • 找到最大合适的区间即可

代码:

#include 

using namespace std;

const int SIZE = 1e5 + 5;
pair mp[SIZE];
long long sum[SIZE];

int main(int argc, char const *argv[])
{
    int n, m;
    long long l, r;
    while (~scanf("%d %d", &n, &m))
    {
        for (int i = 0; i < n; ++i)
        {
            scanf("%I64d %I64d", &l, &r);
            mp[i] = make_pair(l, r);
        }
        sort(mp, mp + n);
        // for (int i = 0; i < n; ++i)
        // {
        //     printf("%I64d %I64d\n", mp[i].first, mp[i].second);
        // }

        int index = 0;
        for (int i = 0; i < n; ++i)
        { // 合并重叠区间
            int step = i+1;
            long long last = mp[i].second;
            while (step < n && mp[step].first <= last)
            {
                last = max(last, mp[step].second);
                ++step;
            }
            mp[index++] = make_pair(mp[i].first, last);
            i = step - 1;
        }

        sum[0] = 0;
        long long ans = m;
        for (int i = 1; i < index; ++i)
        {
            sum[i] = mp[i].first - mp[i-1].second - 1 + sum[i-1];
        }

        for (int l = 0, r = 0; l < index && r < index; ++l)
        {
            while (r < index && sum[r] - sum[l] <= m) ++r;
            long long x = m - (sum[r-1] - sum[l]);
            ans = max(ans, mp[r-1].second-mp[l].first + 1 + x);
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(百度之星,acm,hdu,贪心)