NOIP2012提高组 开车旅行 解题报告
2016-03-18 19:35
239 查看
开车旅行
题目描述
样例输入
样例输出
70分算法
暴力预处理出对于每一个点他右边最近、次近的点的编号,对于每一个询问,暴力模拟开车过程即可。100算法
和上面一样我们得预处理出每一个点最近、次近的点得编号,但我们不可以使用O(n2)的算法。预处理方法一:线段树。线段树维护三个值,区间内最小值、最大值、数的个数。从右往左找(n~1),当找到第i个点时,第i+1个点到第n个点的高度值已经更新过了线段树。通过线段树找出高度比Hi大的最小、次小值,以及找出高度比Hi小的最大、次大值,便可以更新第i个点的最近、次近的点的编号了。因为Hi的值可能很大,会空间超限,所以做之前需要离散化一次。
预处理方法二:双向链表。相比线段树,不需要离散化,但是细节多,调试较麻烦。先将Hi从小到大排序,将两两相邻的两个点连起来。再从前往后枚举i,对于每一个点i,找出它后面连着的两个点(即为大于Hi的最小、次小点)和找出它前面连着的两个点(即为小于Hi的最大、次大点),这样就可以更新出第i个点的最近、次近点。之后,再将第i的点从链表中删去,将其前后的两个元素相连起来。
预处理完毕后,就可以开始求答案了。
如果A从x点开车至y点,然后B从y点开车到z点,则我们视为x向z来了一条边,我们称从x开车到z成为“一轮”。
接下来我们要求出在点i开车经过了2j轮后到达的点的编号,设其为m[i][j]。首先,从后往前枚举i,我们可以通过预处理出来的数据求出m[i][0],之后对于每一个m[i][j]我们可以从m[i][j-1]转移过来。(设k=m[i][j-1]),则m[i][j]=m[k][j-1],即等于i跳了两次2j−1轮,即2j轮,跳到不能跳为止。同时处理一下A开过的路程和B开过的路程。
上面做的一切都是为了接下来的答案求值。接下来要介绍一种算法——倍增。倍增,顾名思义,就是成倍成倍的增长。第一次先开217轮(最多),第二次再开216轮,然后215轮、214轮……可以跳2j轮便跳(即不会越界),不行就不跳。此时开车开到再也开不了为止,这个点便是终点。这样就可以在很短的时间内求出答案。
注:答案会很大,需要开int64(long long)
相关文章推荐
- 知乎日报(Know almost daily chrome version)
- HDU 5101 Select(vector)
- Openfire实现QQ群功能
- 【Matlab】函数imread的返回值
- sugue生命周期,prepareforsegue
- PCA降维
- Android笔记-自定义适配器
- 广播在服务中接收能耗时操作吗
- HDOJ 1091 A+B for Input-Output Practice (III)
- Java main方法
- docker入门
- Android中服务的生命周期与两种方式的区别
- HDU 2203 亲和串
- Mysql索引原理
- 一个链表L 一个链表P 包含升序排列的整数 操作PrintLots(L,P)将打印L中那些由P所指定的位置上的元素
- 解决Xcode会出现的问题
- Struts2 的标签
- snmp常见操作
- Mousejack Hacking : 如何利用MouseJack进行物理攻击
- 关于struts2接受参数