题目

题目描述

有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. 辨别 ShopEX Ecshop

    御剑可以识别ShopEX 或者 Ecshop 特征 ShopEX : 蓝色的icon js里有很多Cookie. <link rel="stylesheet" href=&q ...

  2. 你所不知道的mybatis居然也有拦截器

    对于mybatis的拦截器这个想法我来自于三个地方 也就是下面这个三个地方是可以使用的,其他的情况需要开发人员根据实际情况来使用. 1.对于分页的查询,我们可以对于分页的方法采用比较规范的命名,然后根 ...

  3. Mayor's posters问题处理

    题目的感悟: /*这道题的想法是先开一个数组,先构造一颗线段树,然后每次都进行一次更新最后我们在访问的时候只要看最外层还剩下那些数字,对他们进行统计然后将结果返回即可.这道题的难度本来是不大的,思路非 ...

  4. php---数组序列化

    有两种选择:serialize,json_encode. 需求:对数组进行序列化后保存在文件中,以便爬虫来抓取文件.并且序列化后的字符串只有一行,不希望在该字符串中出现换行,即使数组中某个元素中有换行 ...

  5. PHP正则表达式试题

    1.POSIX正则表达式扩展在PHP哪个版本被废弃了 2.请写出匹配任意数字,任意空白字符,任意单词字符的符号? 3.执行一个正则表达式匹配的函数是什么?返回的结果有哪些? 4.执行一个全局正则表达式 ...

  6. Codeforces Round #372 (Div. 2) C 数学

    http://codeforces.com/contest/716/problem/C 题目大意:感觉这道题还是好懂得吧. 思路:不断的通过列式子的出来了.首先我们定义level=i, uplevel ...

  7. 确定当前Python环境中的site-packages目录位置

    引入“搜索路径”这个概念是因为在使用import语句时,当解释器遇到import语句,如果模块在当前的搜索路径就会被导入. 搜索路径是一个解释器会先进行搜索的所有目录的列表. 那么python如何添加 ...

  8. Lua 垃圾收集机制

    1. 问题:一款用Lua做的游戏,玩了一段时间后会变卡 因为知道lua是有自动管理内存的机制,所以之前一直没有关注过lua内存的问题.所以今天好好的查看了lua垃圾收集机制.看了一下Lua的Garba ...

  9. windows下python+Django+eclipse开发环境的配置

    1.JDK环境的安装 在http://www.java.com/zh_CN/download/faq/develop.xml 页面下,点击JDK下载,下载所需的jdk版本.直接点击安装即可. 2.py ...

  10. 2016湖南省赛--A题--2016

    2016 [TOC] Description 给出正整数 n 和 m,统计满足以下条件的正整数对 (a,b) 的数量: 1. 1≤a≤n,1≤b≤m; 2. a×b 是 2016 的倍数. Input ...