当前位置: 首页 > news >正文

P1204 [USACO1.2] 挤牛奶Milking Cows

题目描述

三个农民每天清晨 555 点起床,然后去牛棚给三头牛挤奶。

第一个农民在 300300300 秒 (从 555 点开始计时) 给他的牛挤奶,一直到 100010001000 秒。第二个农民在 700700700 秒开始,在 120012001200 秒结束。第三个农民在 150015001500 秒开始,210021002100 秒结束。

期间最长的至少有一个农民在挤奶的连续时间为 900900900 秒 (从 300300300 秒到 120012001200 秒),而最长的无人挤奶的连续时间(从挤奶开始一直到挤奶结束)为 300300300 秒 (从 120012001200 秒到 150015001500 秒)。


你的任务是编一个程序,读入一个有 nnn 个农民挤 nnn 头牛的工作时间列表,计算以下两点(均以秒为单位):

最长至少有一人在挤奶的时间段。

最长的无人挤奶的时间段。(从有人挤奶开始算起)

输入格式

第一行一个正整数 nnn

接下来 nnn 行,每行两个非负整数 l,rl,rl,r,表示一个农民的开始时刻与结束时刻。

输出格式

一行,两个整数,即题目所要求的两个答案。

输入输出样例 #1

输入 #1

3
300 1000
700 1200
1500 2100

输出 #1

900 300

说明/提示

【数据范围】 :对于 100%100\%100% 的数据,1≤n≤50001\le n \le 50001n50000≤l≤r≤1060 \le l \le r \le 10^60lr106

USACO Training Section 1.2

思路分析

✅ 题目本质:本题是一个典型的区间合并问题。

给出若干个时间段 [li,ri][l_i, r_i][li,ri],表示每个农民在这段时间内挤奶。你的任务是从这些区间中:

  1. 求出最长的“连续有人挤奶”的时间段长度

  2. 求出最长的“连续没有人挤奶”的时间段长度

🌟 对所有区间按开始时间升序排序

合并区间时,你需要保证——当你扫描到第 iii 个区间时,所有开始时间 ≤≤ 当前区间开始时间 的区间都已经被处理过。

只有这样才能正确判断“是否重叠”以及“该怎么更新右端点”。

这个条件恰好由「按开始时间升序」保证,而「按结束时间升序」无法保证。

结束时间从小到大排序的反例:

农民区间
A(1, 10)
B(2, 5)
C(12, 15)

按结束时间排序 → (B 2‑5), (A 1‑10), (C 12‑15)

处理 B (2‑5),当前合并段 = [2, 5]

遇到 A (1‑10)

start=1 小于 当前合并段的 end=5,程序会认为可以“合并”,并更新 end = max(5, 10) = 10

合并段变成 [2, 10],把 1 到 2 这段空闲错过了!最终:得到最长有人挤奶 2‑10,真正答案应该是 1‑10

排序顺序把起点 111 的区间放到后面来处理,导致漏算。

🌟 线性扫描这些排好序的区间,维护一个当前合并段 [be, ed]

将下一个区间加入当前合并段:

  • 如果下一个区间的起点在当前合并段的末尾之后(start > ed

    • 当前合并段结束了,更新最大有人时间;

    • 这两个区间之间是空隙,更新最大无人时间;

    • 用新的区间重启合并段 [be, ed] = [start, end]

  • 否则(存在重叠或相接)

    • 将当前合并段的右端点更新为 ed = max(ed, end),继续扩展合并段

🌟 扫描结束后再处理一次最后的合并段

最后一个合并段可能是最长的,不能遗漏

🌟 记录两个值

  • mx1:所有合并段中最长的挤奶时间

  • mx2:合并段之间最长的无人时间

🧩 第一步:读入并排序

for(int i = 1; i <= n; i++) {cin >> x >> y;p[i] = make_pair(x, y);
}
sort(p + 1, p + 1 + n);
  • 读取每个农民的挤奶时间区间 [x, y]

  • 使用 pair<int, int> 存入数组 p[i]

  • 调用 sort()start 升序排序区间

✅ 第二步:初始化第一个区间为当前合并段

int be = p[1].first;      // 当前合并段起点
int ed = p[1].second;     // 当前合并段终点
int mx1 = ed - be;        // 当前最长有人时间段长度
int mx2 = 0;              // 当前最长无人时间段长度(初始为0)
  • 将排序后的第一个时间区间作为当前的合并区间的起点和终点;
  • 初始化最长有人挤奶时间段 mx1 为第一个区间的长度;
  • 初始化最长无人时间段 mx2000,表示当前还没有无人段。

✅ 第三步:扫描剩余区间并尝试合并

for(int i = 2; i <= n; i++) 
{if(p[i].first > ed) {// 区间不重叠,出现无人时间段mx1 = max(mx1, ed - be);              // 更新最长有人时间段mx2 = max(mx2, p[i].first - ed);      // 更新最长无人时间段be = p[i].first;                      // 启动新的合并段起点ed = p[i].second;                     // 启动新的合并段终点} else {// 区间重叠或相接,合并区间ed = max(ed, p[i].second);            // 更新合并段终点}
}
  • 从第二个区间开始,逐个遍历剩余时间段;
  • 判断当前区间是否与已有合并段重叠或相接:
    • 不重叠(当前区间的开始时间 > 合并段结束时间):
      • 说明出现了无人时间段,先更新最长有人时间段 mx1
      • 更新最长无人时间段 mx2(当前区间起点减去合并段终点);
      • 重置合并段为当前区间;
    • 重叠或相接
      • 合并当前区间,更新合并段终点为更大的结束时间。

✅ 第四步:处理最后一个合并段

mx1 = max(mx1, ed - be);
  • 遍历完所有区间后,最后一个合并段可能是最长的有人时间段;
  • 因此需要用 mx1 = max(mx1, ed - be) 再次更新最长有人时间段。

✅ 第五步:输出结果

cout << mx1 << " " << mx2 << endl;
  • mx1:最长连续有人挤奶的时间段长度;
  • mx2:最长连续无人挤奶的时间段长度。

完整代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3 + 9;pair<int, int> p[maxn];int main()
{int n;cin >> n;for (int i = 1; i <= n; i++){int x, y; // 开始时间 结束时间cin >> x >> y;p[i] = make_pair(x, y);}sort(p + 1, p + 1 + n); // 开始时间从小到大排序int mx1 = p[1].second - p[1].first, mx2 = 0, ed = p[1].second, be = p[1].first;for (int i = 2; i <= n; i++){if (p[i].first > ed){mx1 = max(mx1, ed - be);be = p[i].first;                 // 最新的开始时间mx2 = max(mx2, p[i].first - ed); // 当前的开始时间 减去 上一次的结束时间ed = p[i].second;}else{ed = max(ed, p[i].second);}}mx1 = max(mx1, ed - be); // 一直连续cout << mx1 << " " << mx2 << endl;return 0;
}
http://www.dtcms.com/a/274157.html

相关文章:

  • 如何设置直播间的观看门槛,让直播间安全有效地运行?
  • 云原生周刊:镜像兼容性
  • 假日流量红利:如何用ASO策略抢占季节性下载高峰?
  • 不同质押周期对代币价格稳定性的具体影响及数据支撑
  • MinIO文件存储服务工具详细使用指南
  • 和服腰封改造:3种解构主义造型的东方美学新解
  • 2025年亚太中文赛赛题浅析-助攻快速选题
  • 【氮化镓】100 V GaN晶体管在关态应力下的双退化
  • Spring Boot中请求参数读取方式
  • HTTP 请求方法详解:GET、POST、PUT、DELETE 等
  • Python中类静态方法:@classmethod/@staticmethod详解和实战示例
  • LeetCode 278. 第一个错误的版本
  • 基于生产者消费者模型的线程池【Linux操作系统】
  • mysql中的自增ID
  • 物联网-ESP8266
  • API、MCP Client、MCP Server、LLM之间的业务逻辑关系
  • 医疗预约系统中的录音与图片上传功能实现:Vue3+Uniapp 实战
  • 在线重装 Proxmox VE
  • Swift中SwiftyJSON使用详情
  • 墙裂推荐!McpStore库三行代码为Agent添加MCP能力
  • 业务建模如何让金融数字化转型 “轻” 装上
  • CentOS7环境安装包部署并配置MySQL5.7
  • 什么是proxy
  • 使用浏览器inspect调试wx小程序
  • 构建基于表单配置的 Jenkins 测试项目(接口、UI、APP、Jmeter)
  • 加速市场反馈,助力产品迭代升级​
  • 如何使用 Python 删除 Excel 中的行、列和单元格 – 详解
  • IAR携手矽力杰与普华基础软件,共推RISC-V车规芯片高安全应用落地
  • docker 启动中间件
  • Python 数据建模与分析项目实战预备 Day 2 - 数据构建与字段解析(模拟简历结构化数据)