挤牛奶&&校门外的树

挤牛奶

农夫去牛场给奶牛们挤奶。

现在从 5 点开始按秒计时,第一名农夫在第 300 秒开始给牛挤奶,并在第 10001000 秒停止挤奶。

第二名农夫在第 700 秒开始给牛挤奶,并在第 1200 秒停止挤奶。

第三名农夫在第 1500 秒开始给牛挤奶,并在第 2100 秒停止挤奶。

从开始挤奶到挤奶完全结束,这一期间,至少存在一名农夫正在挤奶的连续时间段的长度最长为 900 秒(第 300 秒至第 1200 秒),完全没有任何农夫在挤奶的连续时间段的长度最长为 300 秒(第 1200 秒至第 1500 秒)。

现在给你 NN 名农夫挤 NN 头奶牛的工作时间表,请你求出:

  1. 至少存在一名农夫正在挤奶的连续时间段的最长长度。
  2. 没有任何农夫在挤奶的连续时间段的最长长度。

注意:本题中给出的所有时间均为时刻(时间点),因此在本题中挤奶区间 [100,200][100,200] 和 [201,300][201,300] 中间会有长度为 11 秒的间歇时间。

输入格式

第一行包含整数 N,表示农夫数量。

接下来 N 行,每行包含两个非负整数 l,r,表示农夫挤奶的开始时刻和结束时刻。

输出格式

共一行,包含两个整数,分别表示最长连续挤奶时间以及最长连续无人挤奶时间。

数据范围

1≤N≤5000
1≤l≤r≤106

输入样例:
3
300 1000
700 1200
1500 2100
输出样例:
900 300

合并区间的做法,按照每个区间的左端点进行排序,然后根据下一个区间的左端点是否比上一个区间的右端点小,如果小,表明这个两个区间有重叠的部分,使上一个区间的右端点等于下一个区间的有端点,达到合并区间的目的

#include <iostream>
#include <algorithm>
using namespace std;
struct f {
    int a;
    int b;
}arr[5005];
bool cmp(f c, f d)//按左端点排序
{
    return c.a < d.a;
}
int main(void)
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> arr[i].a >> arr[i].b;
    }
    sort(arr, arr + n, cmp);
    int l = arr[0].a, r = arr[0].b;//初始维护区间为第一个区间的左右端点
    int max1 = r-l,max2 = 0;//max1为最长挤奶时间(初始为第一个区间的长度),max2为最长不挤奶时间
    for (int i = 1; i < n; i++)
    {
        if (arr[i].a <= r)//  例如 【1 5】,[2 6】或[1,5],[2,4]这两种情况,选取最大的端点进行更新
            r = max(arr[i].b,r);  //如果两个区间有重叠的部分,更新旧区间的右端点   
        else
        {
            max1 = max(max1, r - l);//如果区间不重叠,就计算区间的最大值,和区间间隙的最大值
            max2 = max(arr[i].a - r,max2);
            l = arr[i].a, r = arr[i].b;//更新维护区间的端点
        }
    }
    max1 = max(max1, r - l);//最后别忘了还有区间没有计算
    cout << max1 << ' ' << max2;
    return 0;
}
//实际区间长度计算的过程中,不一定是r-l,也可能是r-l+1等等,下面的校门外的树,就是r-l+1来计算树的数目

校门外的树

某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。

我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。

由于马路上有一些区域要用来建地铁。

这些区域用它们在数轴上的起始点和终止点表示。

已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。

现在要把这些区域中的树(包括区域端点处的两棵树)移走。

输入格式

输入文件的第一行有两个整数L和M,L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。

接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

输出格式

输出文件包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。

数据范围

1≤L≤10000,
1≤M≤100

输入样例:
500 3
150 300
100 200
470 471
输出样例:
298

两种做法来做

//利用差分数组的思想,将被移走的树进行标记
#include <iostream>
#include <algorithm>
using namespace std;
int arr[10005];
int n, m,a,b;
int main(void)
{
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        cin >> a >> b;
        arr[a]++;
        arr[b + 1]--;
    }
    int sum = 0,num = n;
    for (int i = 0; i <= n; i++)
    {
        sum += arr[i];
        if (sum > 0)num--;
    }
    cout << num +1<< endl;
    return 0;
}
//利用区间合并的思想
#include <iostream>
#include <algorithm>

using namespace std;
struct f {
    int a;
    int b;
}arr[101];
bool cmp(f c, f d)
{
    return c.a < d.a;
}
int main(void)
{
    int m, n;
    cin >> m >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> arr[i].a >> arr[i].b;
    }
    sort(arr, arr + n, cmp);
    int l = arr[0].a, r = arr[0].b;
    int sum = 0;//用来计算合并区间以后的总长度
    for (int i = 1; i < n; i++)
    {
        if (arr[i].a <= r) r = max(arr[i].b, r);
        else 
        {
            sum += r - l + 1;//注意要加一
            l = arr[i].a, r = arr[i].b;
        }
    }
    sum += r - l + 1;
    cout << m + 1 - sum << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值