1. 问题描述:

John 打算驾驶一辆汽车周游一个环形公路。公路上总共有 n 个车站,每站都有若干升汽油(有的站可能油量为零),每升油可以让汽车行驶一千米。John 必须从某个车站出发,一直按顺时针(或逆时针)方向走遍所有的车站,并回到起点。在一开始的时候,汽车内油量为零,John 每到一个车站就把该站所有的油都带上(起点站亦是如此),行驶过程中不能出现没有油的情况。任务:判断以每个车站为起点能否按条件成功周游一周。

输入格式

第一行是一个整数 n,表示环形公路上的车站数;接下来 n 行,每行两个整数 pi,di,分别表示表示第 i 号车站的存油量和第 i 号车站到顺时针方向下一站的距离。

输出格式

输出共 n 行,如果从第 i 号车站出发,一直按顺时针(或逆时针)方向行驶,能够成功周游一圈,则在第 i 行输出 TAK,否则输出 NIE。

数据范围

3 ≤ n ≤ 10 ^ 6,
0 ≤ pi ≤ 2 × 10 ^ 9,
0 ≤ di ≤ 2 × 10 ^ 9

输入样例:

5
3 1
1 2
5 2
0 1
5 4

输出样例:

TAK
NIE
TAK
NIE
TAK
来源:https://www.acwing.com/problem/content/description/1090/

2. 思路分析:

这道题目其实有很多种做法,由题目的数据范围可以知道我们不能够使用O(n ^ 2)的算法来解决,下面使用单调队列优化来的思路解决这个题目;首先这道题目是一个环,对于环形的题目我们知道有一个通用的技巧是将环形转化为链来处理,具体的做法是直接复制一遍原数组并且将其添加到原数组的后面,对于任意一个长度为n站点围成的一圈都可以在长度为2n的链中找到答案;因为求解的是由当前的站点是否能够完整周游一周,所以我们先预处理一下题目中的数据,将每一个位置的权值置为当前站点的油量减去这个站点到下一个站点的距离,并且我们可以预处理每一个位置权值相加的结果,也即计算以起点开始的每一段的前缀和,方面后面处理;我们要求解的是能否从一个起点出发到达终点等价于所有的前缀和都是大于0的,也等价于前缀和的最小值是大于等于0的,这样就可以转化为长度为n的单调队列问题,也即求解长度在n之内的区间最值问题。反正求解区间长度的最值需要想到的是单调队列。因为这道题目可以从顺时钟走一圈也可以从逆时钟走一圈,并且这两个方向在处理的时候有些细节是不一样的,所以需要做两遍单调队列优化。其实这道题目是135题最大子序列的扩展,135题求解的是一个长度为n的区间最值,这道题目求解的是n个区间长度的最值问题;首先我们可以先求解顺时钟走一圈的过程(在做单调队列优化前已经处理好了前缀和数组了),因为求解的是从当前的第i个站点出发的区间最值是否大于0所以前缀和是以当前这个位置向右边延伸最多长度为n个距离,求解每一段以当前位置i开始的前缀和的最小值,所以可以从右边往前枚举,这样枚举到i这个位置的时候说明单调队列中已经求解出了以这个位置i后面的最多长度为n的区间的前缀和的最小值,这个时候需要判断当前这个位置的前缀和是否小于等于队头元素的前缀和,如果小于等于说明以当前这个位置开始每一段前缀和都是大于等于0的,这个可以自己画一下比较好理解,因为当前的队头元素是最小的,所以以这个位置开始的每一段只有大于等于0最终到队头位置的区间和才有可能是大于等于第i个站点的前缀和的,所以当大于等于的时候是可以周游一圈的;注意顺时钟做的计算前缀和的时候是不包含第i个站点的前缀和的,所以答案是res[i + 1] = 1而不是res[i] = 1,而在逆时钟做一遍的时候是包含第i个站点的前缀和的,需要区别一下(原因是前缀和保存的含义是不一样的),这两个过程可以看成是对称的,画图其实很好理解。

3. 代码如下:

class Solution:# 这道题目本质上是135题最大子序和的扩展, 这里求解的n段前缀和是否满足要求, 135题求解的是一段def process(self):n = int(input())# oil[i]为第i个站点的油量, dis[i]为第i个站点到下一个站点的距离oil, dis = [0], [0]# 下标从1开始存储元素方便后面处理for i in range(n):a, b = map(int, input().split())oil.append(a)dis.append(b)# 声明前缀和列表s = [0] * (2 * n + 2)# 顺时针求解每一个点到是否可以完整走一圈for i in range(1, n + 1):# 因为是复制一遍接在了原数组后面所以第i + n个位置与第i个位置的元素是一样的s[i] = s[i + n] = oil[i] - dis[i]   # 累加前缀和, 前缀和存储的是这么多段的剩余油量for i in range(1, 2 * n + 1):s[i] += s[i - 1]q = [0] * (2 * n + 2)hh, tt = 0, 0# q[0]为哨兵, 因为求解的是以当前站点i顺时钟是否可以绕一周所以可以逆时终计算长度为为n之内的前缀和的最小值判断是否所有长度在n之内的前缀和是否满足条件q[0] = 2 * n + 1res = [0] * (n + 1)for i in range(2 * n, -1, -1):# 区间长度大于了n说明hh头指针需要往后移动一位if q[hh] > i + n: hh += 1# 注意后面的下标是i + 1, 顺时钟做的时候不包含第i个站点的情况if i < n:if s[i] <= s[q[hh]]: res[i + 1] = 1# 单调队列优化过程while hh <= tt and s[q[tt]] >= s[i]: tt -= 1tt += 1q[tt] = i# 逆时钟做一遍(其实与前面的过程是对称的), 注意第0个距离需要赋值为第n个站点的距离dis[0] = dis[n]# 处理前缀和for i in range(1, n + 1):# 注意与顺时钟做的时候的区别因为是逆时钟所以需要减去上一个元素的距离s[i] = s[i + n] = oil[i] - dis[i - 1]for i in range(1, 2 * n + 1):s[i] += s[i - 1]hh, tt = 0, 0q[0] = 0for i in range(1, 2 * n + 1):if q[hh] + n < i: hh += 1if i > n:# 逆时钟做的时候包含第i个站点的情况if s[i] >= s[q[hh]]: res[i - n] = 1while hh <= tt and s[q[tt]] <= s[i]: tt -= 1tt += 1q[tt] = ifor i in range(1, n + 1):# 只要有一个满足条件说明就是符合要求的if res[i] == 1: print("TAK")else: print("NIE")if __name__ == "__main__":Solution().process()

1088 旅行问题(单调队列优化)相关推荐

  1. Acwing -- 单调队列优化的DP问题

    文章目录 引入 acwing154 滑动窗口 应用 135 最大子序和 1088.旅行问题 AcWing 1087. 修剪草坪28 AcWing 1089. 烽火传递 AcWing 1090. 绿色通 ...

  2. 单调队列优化的DP问题

    概述 单调队列就是通过排除求最值时候的冗余,从而是队列具有性质,可以方便求解问题. DP的两个阶段: 朴素DP的基本原理--闫氏DP分析法 对朴素DP进行优化 闫氏DP分析法的拓展 :在一个有限的集合 ...

  3. 单调队列优化DP 上 day46

    我超 好jian的t宝 今天也没有看到jls登顶www 一些小理解:dp就是用集合来概括 这样就可以用递推的方式来最优解优化 而dp的状态自然千奇百怪 可谓条条大路 AcWing 135. 最大子序和 ...

  4. 提高篇 第五部分 动态规划 第5章 单调队列优化动态规划

    单调队列:是一种双端除列,其内部元素具有单调性. 最大队列 最小队列 操作: .插入:新元素插入队尾,删除除尾元素,直到找到插入后不会破坏单调性的为止. .获取最大(最小)值,访问队首元素. 单调队列 ...

  5. 算法笔记--单调队列优化dp

    单调队列:队列中元素单调递增或递减,可以用双端队列实现(deque),队列的前面和后面都可以入队出队. 单调队列优化dp: 问题引入: dp[i] = min( a[j] ) ,i-m < j ...

  6. 多重背包单调队列优化思路_多重背包之单调队列优化理论性总结

    多重背包之单调队列优化: 若用F[j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m = min(n, j / v).放入背包的第i种物品的数目可以是:0.1.2--, ...

  7. tyvj1305 最大子序和 【单调队列优化dp】

    描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7 当m=2或m=3时,S=5+1=6 输 ...

  8. poj 2373(单调队列优化dp)

    在长为L(<=1000000)的草地(可看成线段)上装喷水头,喷射是以这个喷水头为中心,喷水头的喷洒半径是可调节的调节范围为[a,b].要求草地的每个点被且只被一个喷水头覆盖,并且有些连续区间必 ...

  9. poj 1821(单调队列优化dp)

    题意:有一道线性篱笆由N个连续的木板组成.有K个工人,你要叫他们给木板涂色.每个工人有3个参数:L 表示 这个工人可以涂的最大木板数目,S表示这个工人站在哪一块木板,P表示这个工人每涂一个木板可以得到 ...

  10. POJ - 3926 Parade(单调队列优化dp)

    题目链接:点击查看 题目大意:给出一个n*m的街道,其中有(n+1)*m条街道,每条街道都有一个值,现在我们需要从最下面的任意一点出发,到达最上面的任意一点结束,问如何规划路线能让沿途经过的街道的权值 ...

最新文章

  1. 语义网所谓的“本体”的具体例子是什么?人工智能
  2. 编辑PDF文档,Word 2013可以是您的选择
  3. vendor自动恢复_解决 vendor 中存在大小写变更问题
  4. CentOS7攻克日记(三) —— 安装Python3.6
  5. PyTorch ResNet 测试
  6. mysql 5.7 备份innodb_mysql5.7 innodb数据库备份工具Xtrabackup的安装
  7. 【kruskal】【倍增】严格次小生成树(P4180)
  8. (3)Node.js APIS
  9. oracle基础入门(四)
  10. SQL Server 2000 Service Pack 4 升级指南
  11. Undefined class constant ‘SERIALIZER_IGBINARY‘ 解决方法
  12. PS绘制的路径不见了
  13. 分布式数据库设计——分布式数据库的基础概念
  14. linux 组建raid0教程,用两块硬盘组建RAID0磁盘阵列简单教程(图文详解)
  15. 卡尔曼滤波原在温度测量中的应用
  16. 连接数据库失败,难道MySQL 5.7客户端与8.0数据库不兼容?
  17. 微信小程序解密失败的可能原因
  18. 交易者应该学习的东西
  19. 自费送苹果AirPods,机械键盘,10本书籍多重福利
  20. 配制ubuntu - 使用大全整理 (其中有转载内容,如果有您的文章,请与我联系,我将加入你的名称)

热门文章

  1. python画行向日葵_如何用Python画一朵太阳花
  2. 电脑倒计时调用写好的html,HTML网页 倒计时(入门级)
  3. cmd怎么查看当前静态路由_怎么使用cmd设置添加电脑上静态路由
  4. PCA主成分分析去噪与降维
  5. Server-sent events(SSE) EventSource 客户端使用与服务器基础实现(基于Node.js)
  6. 使用Transformer学习动态多层次的交通时空特征
  7. MES系统生产派工提高注塑行业生产效率
  8. Unity3D制作塔防类游戏
  9. vue加载m3u8视频格式
  10. 博客推广技巧:如何通过博客推广并实现营销