codeforces 343C Read Time 二分 + 贪心
2015-08-25 14:35
260 查看
http://codeforces.com/problemset/problem/343/C
题意:
有一些磁头,给出了起始的位置,给出了一些磁盘中需要访问的地点。求这些磁头移动的最小的次数。
思路:
二分找出满足要求的最小的时间,对于当前尝试的时间进行贪心判断是否可用。对于贪心,因为每一个磁头都需要读到还没有人读过的最左边的地方。如果这个都不能满足,那么这个时间是不可以的。
在这基础上,对于同样的这么多时间,尽可能的让这个磁头读到能读到的最右边,这样就可以将还没有读过的地方尽可能的往右推。
如果这样最后能够将所有读取完,那么这个时间是可以的。
确定能读到的最右边(当然首先要保证读到还未读过的最左边,这是前提。),同样的时间,两种行走的方式,1)先向左走,后向右走。能向右走t−2∗(h[i]−p[step])t - 2*(h[i]-p[step])的距离。2)先向右走,后想左走。能向右走(t−(h[i]−p[step])/2(t - (h[i]-p[step])/2的距离。选择一个最大的。
再更新尚未访问的最左边的位置。
总结:
类似最大化最小值,最小化最大值的题目做了有几道了,但是感觉还是没有什么感觉,经常就想不到,对于直接二分答案这种思想还会不够敏感吧。
总结一下这些最大化最小值等这类问题吧。
首先要寻找的这个答案是在一个确定的范围里,超过多少或小于多少就不能作为答案,题目往往要求的是这个答案的最大值,或者最小值, 就要最大化或者最小化这个答案。要找的这个就肯定是在边界附近,对于这题来说就是再小一点的时间就不可以满足了。
对于这样就要想到二分找答案的方法,因为这个就是一个连续单调的,在一个点将满足与不满足的分开。
这样的题还有一个地方就是需要构造出一个判断当前找的这个答案是否满足条件的方法,需要快速的判断这个是否可以满足。这题里面运用的就是贪心。
题意:
有一些磁头,给出了起始的位置,给出了一些磁盘中需要访问的地点。求这些磁头移动的最小的次数。
思路:
二分找出满足要求的最小的时间,对于当前尝试的时间进行贪心判断是否可用。对于贪心,因为每一个磁头都需要读到还没有人读过的最左边的地方。如果这个都不能满足,那么这个时间是不可以的。
在这基础上,对于同样的这么多时间,尽可能的让这个磁头读到能读到的最右边,这样就可以将还没有读过的地方尽可能的往右推。
如果这样最后能够将所有读取完,那么这个时间是可以的。
确定能读到的最右边(当然首先要保证读到还未读过的最左边,这是前提。),同样的时间,两种行走的方式,1)先向左走,后向右走。能向右走t−2∗(h[i]−p[step])t - 2*(h[i]-p[step])的距离。2)先向右走,后想左走。能向右走(t−(h[i]−p[step])/2(t - (h[i]-p[step])/2的距离。选择一个最大的。
再更新尚未访问的最左边的位置。
总结:
类似最大化最小值,最小化最大值的题目做了有几道了,但是感觉还是没有什么感觉,经常就想不到,对于直接二分答案这种思想还会不够敏感吧。
总结一下这些最大化最小值等这类问题吧。
首先要寻找的这个答案是在一个确定的范围里,超过多少或小于多少就不能作为答案,题目往往要求的是这个答案的最大值,或者最小值, 就要最大化或者最小化这个答案。要找的这个就肯定是在边界附近,对于这题来说就是再小一点的时间就不可以满足了。
对于这样就要想到二分找答案的方法,因为这个就是一个连续单调的,在一个点将满足与不满足的分开。
这样的题还有一个地方就是需要构造出一个判断当前找的这个答案是否满足条件的方法,需要快速的判断这个是否可以满足。这题里面运用的就是贪心。
[code]#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define M 100009 typedef long long ll; int n,m; ll h[M],p[M]; bool judge(ll t) { int step = 0; //表示最左边未读取过的点 for(int i = 0;i < n;i++) { if(step >= m) break; if(h[i] - p[step] > t) return false; //走不到最左边 ll s = h[i]; if(h[i] < p[step]) //当前磁头已经在要读的最左的地方的右边。 s = h[i] + t; else { s = max(s,h[i]+t-2*(h[i]-p[step])); //先左走后右走 s = max(s,h[i]+(t-(h[i]-p[step]))/2); //先右走后左走 } while(step < m && p[step] <= s) step++; //更新最左边未读取的 } if(step < m) return false; return true; } int main() { while(scanf("%d %d",&n,&m) == 2) { for(int i = 0;i < n;i++) scanf("%I64d",&h[i]); for(int i = 0;i < m;i++) scanf("%I64d",&p[i]); ll low = -1,high = -1; if(h[0] < p[0]) //确定high的上限 high = p[m-1] - h[0]; else { high = max((h[0]-p[0])*2+p[m-1]-h[0],(p[m-1]-h[0])*2+h[0]-p[0]); } while(high - low > 1) //找出最小值,边界的判定要小心 { ll mid = (high+low) >> 1; if(judge(mid)) high = mid; //满足缩小上限 else low = mid; } printf("%I64d\n",high); } return 0; }
相关文章推荐
- SourceInsight 增加对Lua语言的支持
- 来自大数据的反思:需要你读懂的10个小故事
- MySQL 常用命令
- 连接地址 打开浏览器
- [LeetCode 242] Valid Anagram
- DataSet用法详细 转
- 用Jquery控制文本框只能输入数字和字母
- jQuery获取,遍历和操作表单元素Select,checkbox,radio
- ZOJ 1649 Rescue
- poj 1376 Robot(bfs)
- 【贪心】[COCI]电话监测
- smarty基础之插件
- vijos1431:守望者的逃离
- Ubuntu 系统 Update-rc.d 命令
- Linux环境下iscsi initiator的应用
- Maven 添加第三方Jar包到本地repositories
- Spring MVC hello world example
- hibernate实体类中为何要重写equals与hashcode方法
- 内连接、左外连接、右外连接、交叉连接区别
- Excel文档上传