题意简述
n首歌循环播放。每首歌有一个欢乐值。播放到一首歌,如果这首歌的欢乐值的两倍小于放过的最大值,则停止。对于每首歌,求出从这首歌开始播放,能放几首歌。n<=1e5。
思路框架
如果全局最小值的两倍>=全局最大值,直接全部输出-1。
数组开三倍。维护一个单调递减的单调队列。现在考虑到$i$,先把$a[i]$入队列。如果$a[i]$两倍小于队首$H$,记录$ans[H]=i-H$,弹出队首。对于没有处理过的位置$i$,直接ans[i]=ans[i+1]+1。输出1~n位置的答案。
具体思路
由于是循环的问题,我们考虑把数组开两倍。但是看到样例二,手动模拟一下,发现这不够,要三倍。
开始分析。显然,$i$位置能播放到的位置肯定<=$i+1$能放到的位置。比如这组数据:1
215
58 37 28 74 28 41 50 34 72 79 45 42 94 54 39
我们计算每个位置能放到的位置,得到这样一个数组:1
3 5 5 5 15 15 15 15 15 15 15 15 15 18 18
(小数据,可以手做做看或者模拟)
设这个数组为$pos$。题目让我们求的就是$pos[i]-i$,并输出。设题目求的是$ans$数组。
那么我们考虑求这个$pos$。如果不是在“转折点”的时候,应该满足$ans[i]=ans[i+1]+1$。
所以我们现在就是要求这些转折点位置的答案。别的位置就直接$ans[i]=ans[i+1]+1$。
求转折点位置及答案
思考:为什么会有“转折”?
比如说第$i$个位置和第$i+1$个位置不一样。那么肯定是因为$i$位置更新了最大值,让最大值变大了,更加容易满足条件,所以答案减少。
能更新最大值的位置,就是转折点。我们用一个单调队列维护即珂(队列里面维护下标)。
入队列的条件
如果有一个元素A比另一个元素B排在后面,然后A还比B大,那么B无论如何也不会更新最大值了。因为,只要能考虑到B,就肯定能考虑到A,而且A还比你大。所以我们的队列,如果新的队尾大于原来的队尾,那么就弹出原来的队尾。换句话说,就是维护一个单调递减的队列。
出队列的条件
如果当前考虑的$i$,满足$a[i]$两倍小于队首$H$,那么如果从$H$开始播放,肯定播放到$i$就停止了,后面就不会再有影响。所以如果发生了这样的情况,就记录队首的答案,并且把它弹出去。
转折点篇 完
代码
1 |
|