六级第二关———坐地铁(1)
我家在北京,去考试会坐地铁去,不过你得先下楼梯,呵呵。
上次我们浅谈了动态规划。这次让一个神秘人出场吧——你们猜猜是谁?
动态规划……
聊聊北京地铁,有两条环线,2号线和10号线,好,小A的城市也有一条环线,不过小A打算玩坏环线。
题目描述
小 A 喜欢坐地铁。地铁环线有 n 个车站,依次以 1,2,⋯,n 标号。车站 i (1≤i<n) 的下一个车站是车站 i+1。特殊地,车站 n 的下一个车站是车站 1。
小 A 会从某个车站出发,乘坐地铁环线到某个车站结束行程,这意味着小 A 至少会经过一个车站。小 A 不会经过一个车站多次。当小 A 乘坐地铁环线经过车站 i 时,小 A 会获得 ai 点快乐值。请你安排小 A 的行程,选择出发车站与结束车站,使得获得的快乐值总和最大。
输入格式
第一行,一个正整数 n,表示车站的数量。
第二行,n 个整数a[i],分别表示经过每个车站时获得的快乐值。
输出格式
一行,一个整数,表示小 A 能获得的最大快乐值。
输入输出样例
输入 #1
4 -1 2 3 0
输出 #1
5
输入 #2
5
-3 4 -5 1 3
输出 #2
5
说明/提示
对于 20% 的测试点,保证 1≤n≤200。
对于 40% 的测试点,保证 1≤n≤2000。
对于所有测试点,保证 1≤n≤2×10^5,−10^9≤a[i]≤10^9。
看完题之后,是不是很像我未曾介绍的区间动态规划?我不会这么折磨你的。但是有一点你要注意, 1≤n≤2×10^5,证明需要O(N)的解法,也就是说,你只能用一层循环或循环套二分。
分析题目,造样例:
北京2号线:
5个车站
快乐值: 2 -34 35 -6767 10
别惊讶,快乐值为-6767的车站说明这站看着就能让人恶心哭,所以为了保证小A不吐,不让他经过这个车站吧。那就是2+-34+35=3了?错!是环线,所以呢可以是10+2+-34+35=13点快乐值!
你想破环成链?先表扬一下,但是错!
你如何保证选中的最大子段长度小于N?保证不了!
那咋做?
看到标签后恍然大悟:
我们简化一下题目:截取一个长度 ≤n 的序列,使它的和最大。那么众所周知,如果要让和最大,那么减掉的就越少越好。
所以我们可以先求出破环成链后的 a 数组的前缀和 sum 数组,然后对于每一个 1≤i≤2n 在确保长度不超过 n 的情况下,减掉一个最小的前缀和,最后取最大值即可。
针对上述思路,单调队列简直再合适不过了。
啥?单调队列是神马?
这题用的是这个:
for(int i=1;i<=2*n;i++){while(!q.empty() && i-(q.front()).id>n){q.pop_front();}mx=max(mx,sum[i]-(q.front()).sum);while(!q.empty() && (q.back()).sum>sum[i]){q.pop_back();}q.push_back({i,sum[i]});}
由于种种原因,本人先不更下面的了,先发布再说。