题目

题目描述

有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. hdu_5293_Tree chain problem(DFS序+树形DP+LCA)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5293 被这题打蹦了,看着题解写的,很是爆炸,确实想不到,我用的DFS序+LCA+树形DP,当然也可以写 ...

  2. Html:upload

    文件上传框 有时候,需要用户上传自己的文件,文件上传框看上去和其它 文本域差不多,只是它还包含了一个浏览按钮.访问者可以通 过输入需要上传的文件的路径或者点击浏览按钮选择需要上传 的文件. 代码格式: ...

  3. 设置ulabel的行间距

    NSString *text = @"我是一个好人,12份绿色购物个 i 认为个人我国 i 加热哦围观 i我国3噢奇怪级我过街天桥哦推荐我她否认"; NSMutableParagr ...

  4. postgres-xl 集体搭建(1)

    安装并编辑脚本 cd /opt/curl -O http://files.postgres-xl.org/postgres-xl95r1beta1.tar.gztar -zxvf postgres-x ...

  5. VS2005--设置Release模式下调试

    今天初略看了下,所谓Release和Debug只是大家和编译器约定的一些生成规则而已,所以调试是无所谓Release和Debug的,只是由于生成的规则不同,可能Release的一些调试结果没Debug ...

  6. Java 反射实例

    实体类:Userpackage com.reflect.model; public class User{ private User(int id, String username, String p ...

  7. Snackbar使用及其注意事项(转)

    http://blog.csdn.net/jywangkeep_/article/details/46405301 Snackbar使用及其注意事项 引言 Snackbar是Android Suppo ...

  8. redhat 安装GCC-4.8.3

    1.下载gcc-4.8.3安装包 gcc各版本浏览地址:http://ftp.gnu.org/gnu/gcc/ yum install gccyum install gcc-c++ 2.将gcc-4. ...

  9. 初识Jmeter(一)

    倒霉熊的推荐: 文本学习网址:http://m.open-open.com/m/doc/category/105 视频学习网址: 软件学习网:http://www.ask3.cn/index.html ...

  10. 异步加载AsyncTask

    private void huodeshuju() {        new AsyncTask<String, Void, String>() {            @Overrid ...