题目

题目描述

有3个农夫每天早上五点钟便起床去挤牛奶,现在第一个农夫挤牛奶的时刻为300(五点钟之后的第300个分钟开始),1000的时候结束。第二个农夫从700开始,1200结束。最后一个农夫从1500开始,2100结束。现在我们可以算出,在一段时间内至少有一个农夫在持续挤牛奶的最长时间间隔为900分钟(1200-300),在他们挤牛奶的过程中,没有人挤牛奶的最长时间间隔为300分钟(1500-1200)。

现在有N个农夫,给出他们每个人挤牛奶的开始时刻与结束时刻。分别计算出在一段时间内至少有一个农夫在持续挤牛奶的最长时间间隔,与没有人挤牛奶的最长时间间隔。

数据范围

  1. 1 <= N <= 5000
  2. 农夫们挤牛奶的开始时刻与结束时刻都小于1000000

样例输入

3
300 1000
700 1200
1500 2100

样例输出

900 300

解题思路

首先按照农夫们的开始时刻进行从小到大排序,然后利用线段覆盖原理,用标记将时间段的开始时刻与结束时刻标好,两个时间段重叠在一起之后就可以看作是一个时间段,这时就应该更新标记。当出现时间段不连续的时候,我们就需要开始更新没有人挤牛奶的开始时刻与结束时刻了。每次更新时间段的标记,我们都应该计算出时间间隔,最终取最大的时间间隔。

排序的时间复杂度为O(NlogN),下面的处理时间间隔操作时间复杂度为O(N),所以这种算法的时间复杂度为O(NlogN)

解题代码

/*
ID: yinzong2
PROG: milk2
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath> using namespace std;
const int maxn = 5000+10; int n;
//flagBegin1与flagEnd1表示long milking periods的起始时刻与结束时刻
//flagBegin2与flagEnd2表示long non-milking periods的起始时刻与结束时刻
int flagBegin1, flagEnd1, flagBegin2, flagEnd2;
int _max1, _max2; struct TimeSeg {
int b, e;
}t[maxn]; bool cmp(TimeSeg x, TimeSeg y) {
if(x.b < y.b) {
return true;
} else if(x.b == y.b) {
return x.e < y.e;
}
return false;
} void work() {
flagBegin1 = t[0].b;
flagEnd1 = t[0].e;
_max1 = flagEnd1-flagBegin1; flagBegin2 = flagEnd2 = t[0].e; for(int i = 1; i < n; i++) {
if(t[i].b <= flagEnd1) {
if(t[i].e > flagEnd1) {
flagEnd1 = t[i].e;
flagBegin2 = flagEnd2 = t[i].e;
}
} else {
_max1 = max(_max1, flagEnd1-flagBegin1);
flagBegin1 = t[i].b;
flagEnd1 = t[i].e; flagEnd2 = t[i].b;
_max2 = max(_max2, flagEnd2-flagBegin2);
flagBegin2 = flagEnd2 = t[i].e;
}
}
printf("%d %d\n", _max1, _max2);
} int main() {
#ifdef MARK
freopen("milk2.in", "r", stdin);
freopen("milk2.out", "w", stdout);
#endif // MARK
while(~scanf("%d", &n)) {
for(int i = 0; i < n; i++) {
scanf("%d%d", &t[i].b, &t[i].e);
}
sort(t, t+n, cmp);
_max1 = _max2 = 0;
work();
}
return 0;
}

解题思路(Type 2)

我们可以用最朴素的办法,将时间复杂度优化为O(N),因为数据量比较小,所以我们可以直接开一个bool类型的数组,来记录挤牛奶的时间,在某一时刻有人挤牛奶那么就赋值为true,否则为false。最后线性的扫描一遍取得最大的时间间隔。

这种方法最关键的地方就是边界的处理,一定要细心。注意题目给的是农夫们挤牛奶的时刻,但是我们要计算的是挤牛奶的时间间隔。例如:某位农夫从1时刻一直到5时刻都在挤牛奶,我们在bool数组里面从1到5都会赋值为true,这样数出来为5,其实时间间隔为4,因为我们要将时刻变为时间间隔,要减去1。

所以我们在赋值的时候需要稍微处理一下,当农夫挤牛奶的时刻为A到B时,我们在数组中记录应该从A+1~B都赋为true,这样便于下面的操作。

解题代码(Type 2)

/*
ID: yinzong2
PROG: milk2
LANG: C++11
*/
#define MARK
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm> using namespace std;
const int maxn = 1e6 + 10; int n;
//申明变量的时候一定不能用C++里面的关键字,例如time[],这样的变量在某些oj有可能会报错
bool _time[maxn]; int main() {
#ifdef MARK
freopen("milk2.in", "r", stdin);
freopen("milk2.out", "w", stdout);
#endif
while(~scanf("%d", &n)) {
memset(_time, false, sizeof(_time));
int b, e;
int first = maxn;
int last = -1;
for(int i = 0; i < n; i++) {
scanf("%d%d", &b, &e);
first = min(first, b+1);
last = max(last, e); //注意边界,我们记录的是时刻,但是要计算的是时间间隔
for(int j = b+1; j <= e; j++) {
_time[j] = true;
}
} bool flag = true;
int cnt1 = 0, cnt2 = 0;
int _max1 = 0, _max2 = 0;
for(int i = first; i <= last; i++) {
if(_time[i] != flag) {
if(flag) {
_max1 = max(_max1, cnt1);
} else {
_max2 = max(_max2, cnt2);
}
cnt1 = cnt2 = 0;
flag = _time[i];
//回退一次,重新开始计数
i--;
} else {
if(flag) cnt1++;
else cnt2++;
}
}
//最后的last一定是true,我们上面的循环没有将最后一段时间间隔进行比较,所以这里需要补充
_max1 = max(_max1, cnt1);
printf("%d %d\n", _max1, _max2);
}
return 0;
}

USACO Section 1.2 Milking Cows 解题报告的更多相关文章

  1. USACO Section1.2 Milking Cows 解题报告

    milk2解题报告 —— icedream61 博客园(转载请注明出处)---------------------------------------------------------------- ...

  2. USACO Section 1.3 Prime Cryptarithm 解题报告

    题目 题目描述 牛式的定义,我们首先需要看下面这个算式结构: * * * x * * ------- * * * <-- partial product 1 * * * <-- parti ...

  3. USACO Section 1.4 Arithmetic Progressions 解题报告

    题目 题目描述 现在给你一个数集,里面的数字都是由p^2+q^2这种形式构成的0 <= p,q <= M,我现在需要你在其中找出一个长为N的等差数列,数列中的第一个数字为a,公差为b,当你 ...

  4. USACO Section 1.3 Combination Lock 解题报告

    题目 题目描述 农夫John的牛从农场逃脱出去了,所以他决定用一个密码锁来把农场的门锁起来,这个密码锁有三个表盘,每个表盘都是环形的,而且上面刻有1~N,现在John设了一个开锁密码,而且这个锁的设计 ...

  5. USACO Section 1.3 Barn Repair 解题报告

    题目 题目描述 某农夫有一个养牛场,所有的牛圈都相邻的排成一排(共有S个牛圈),每个牛圈里面最多只圈养一头牛.有一天狂风卷积着乌云,电闪雷鸣,把牛圈的门给刮走了.幸运的是,有些牛因为放假,所以没在自己 ...

  6. USACO Section 1.3 Mixing Milk 解题报告

    题目 题目描述 Merry Milk Makers 公司的业务是销售牛奶.它从农夫那里收购N单位的牛奶,然后销售出去.现在有M个农夫,每个农夫都存有一定量的牛奶,而且每个农夫都会有自己的定价.假设所有 ...

  7. USACO Section 1.2 Dual Palindromes 解题报告

    题目 题目描述 有一些数(如 21),在十进制时不是回文数,但在其它进制(如二进制时为 10101)时就是回文数. 编一个程序,从文件读入两个十进制数N.S.然后找出前 N 个满足大于 S 且在两种以 ...

  8. USACO Section 1.2 Palindromic Squares 解题报告

    题目 题目描述 输入一个基数B,现在要从1到300之间找出一些符合要求的数字N.如果N的平方转换成B进制数之后是一个回文串,那么N就符合要求.我们将N转换成B进制数输出,然后再将N的平方转换成B进制数 ...

  9. USACO Section 1.1 Broken Necklace 解题报告

    题目 题目描述 有一串项链,它是由红蓝白三种颜色的珠子组成的,b代表蓝色,w代表白色,r代表红色,当它完整的时候是一个闭合的环形.现在它在某一个节点断裂了,之前的环形也随之变成了直线形.从两端开始收集 ...

随机推荐

  1. 网页特效-动态加载JavaScript

    描述: 把一些逻辑独立的JavaScript脚本文件单独加载,是一种常见的JavaScript动态加载技术.可以减少不必要的JavaScript脚本文件的加载,以提高网页浏览速度 代码: <!D ...

  2. Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLIC

    在mysql5中遇到的问题: Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8_unicode_ci,IMPLICIT) f ...

  3. C陷阱与缺陷 第二章

    有关运算符优先级   1. "<<" 和 "+" data8 = data4H << 4 +data4L; 这里本意是让高四位的数据,左 ...

  4. WPF之TabControl控件用法

    先创建实体基类:NotificationObject(用来被实体类继承) 实现属性更改通知接口: using System; using System.Collections.Generic; usi ...

  5. hash随笔

    hash属性是一个可读可写的字符串,是url的锚部分(从#开始).多用于单页面应用中,使其包含多个页面. 定位:通过id来定位 eg: <div id= "part1"> ...

  6. awstats + tomcat + windows

    下载: 1.apache-tomcat-7.0.67 2.ActivePerl-5.22.1.2201-MSWin32-x86-64int-299574.msi 3.awstats-7.4.zip 修 ...

  7. 快学Scala-第九章 文件和正则表达式

    知识点: 1.读取文件中的所有行,可以调用scala.io.Source对象的getLines方法: import scala.io.Source val source = Source.from(& ...

  8. JS-DOM元素灵活查找

    用className选择元素 封装成函数 <title>无标题文档</title> <script> /* window.onload=function () { ...

  9. zookeeper实现分布式锁服务

    A distributed lock base on zookeeper. zookeeper是hadoop下面的一个子项目, 用来协调跟hadoop相关的一些分布式的框架, 如hadoop, hiv ...

  10. DedeCMS中实现在顶层banner中显示自定义登录信息

    一.需求描述 dedeCMS自带的模板中有互动中心模块,如下图所示: 由于会员登陆对我来说不是网站的重要模块且默认DedeCMS的会员中心模块的初始化很慢,常会显示“正在载入中,请稍候...”, 所以 ...