题目

题目描述

有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. STM32F207V 进行DS18B20处理

    1.  DS18B20接口很简单,VCC.DQ.GND三个引脚,VCC采用外部供电3.3V,DQ需上拉电阻,当时按照参考资料上外接4.7K的上拉电阻,GPIO设置的OD无上拉,始终读不到ROM中的64 ...

  2. A框架第一步,传递不同参数.主程序执行对应方法

    访问: www.test.com/admin 1============后台目录:admin (确保单一入口) --有入口文件index.php <?phprequire '../A/a.php ...

  3. ios控件 UILabel

    UILabel 的作用是显示文本 UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 100, 40)]; lab ...

  4. python的历史与优劣

    历史 Python的创始人是Guido van Rossum,在发明Python语言之前Guido曾参与过一门称作ABC的语言的设计,ABC是专门为非专业程序员设计的:Guido在Python语言的设 ...

  5. 尚未配置为Web项目.指定的本地IIS URL http://localhsst/..要打开项目,需要配置虚拟目录 。是否立即创建虚拟目录 解决

    1.编辑.csproj文件 2.修改 UseIIS节点改为false,再次打开程序即可

  6. shell中exec解析

    参考:<linux命令.编辑器与shell编程> <unix环境高级编程> exec和source都属于bash内部命令(builtins commands),在bash下输入 ...

  7. Linq List<String>

    List<string> _year = new List<string>() { "一月", "二月", "三月" ...

  8. cssText笔记

    style.cssText 用来获取/设置元素的样式 设置: <div id= "a" style= "background: red;"> doc ...

  9. c++运行时类型识别(rtti)

    一个简单运行时类型识别 namespace rtti_ex { /* * 类型信息基类 */ class i_type_info { public: // 判断是否是指定类型 bool is(cons ...

  10. druid 文档 和 源码地址

    Druid文档 :https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98 maven仓库:http://c ...