题目
题意:
给定n张唱片,每张唱片都有一个好听度a[i]。某个人选择第i张唱片开始播放,播放完则下一张继续播放,到第n张时下一张为第1张。当某一张唱片的好听度严格小于已经听过的唱片的最大值的一半时,这个人将会停止播放。要求输出对于任意的选择一张唱片i开始,最多能听几张唱片,也可能是无穷多,这时输出-1。
2
≤
n
≤
1
0
5
,
1
≤
a
i
≤
1
0
9
2≤n≤10^5,1≤a_i≤10^9
2≤n≤105,1≤ai≤109
分析:
思考第1张唱片停止的位置,假设为j。那么显然第二张唱片停止的位置一定是大于等于j的,因为第二张唱片开始与第一张唱片开始的区别在于第二张开始的过程中一直少了第一张的好听度,其余均一样。那么这样具有单调性的右端点,我们就可以想到划窗。由于要维护窗口的最大值,所以需要使用单调队列。由于唱片成环(需要开某些倍的数组将环变为线性结构),所以我们需要开3倍的数组(因为可能花费一圈找最大值,然后再一圈停止)。当然右端点超过3*n时自然就是停不下来的了。
#include <iostream>
using namespace std;
int a[300005],q[300005];
int ans[100005];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
int head,tail;
head = tail = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
a[i+n] = a[i];
a[i+2*n] = a[i];
}
int r = 1;
for (int i = 1; i <= n; i++)
{
while( head < tail && q[head] < i ) head ++;
while( head == tail || a[r] * 2 >= a[q[head]] )
{
while( head < tail && a[r] >= a[q[tail-1]] ) tail --;
q[tail] = r;
tail ++;
r ++;
if( r > 3 * n ) break;
}
if( r > 3 * n ) ans[i] = -1;
else ans[i] = r - i;
}
for (int i = 1; i <= n; i++)
{
cout << ans[i];
if( i == n ) cout << '\n';
else cout << ' ';
}
return 0;
}