题意简述
n首歌循环播放。每首歌有一个欢乐值。播放到一首歌,如果这首歌的欢乐值的两倍小于放过的最大值,则停止。对于每首歌,求出从这首歌开始播放,能放几首歌。n<=1e5。
思路框架
如果全局最小值的两倍>=全局最大值,直接全部输出-1。
数组开三倍。维护一个单调递减的单调队列。现在考虑到 ,先把 入队列。如果 两倍小于队首 ,记录 ,弹出队首。对于没有处理过的位置 ,直接ans[i]=ans[i+1]+1。输出1~n位置的答案。
具体思路
由于是循环的问题,我们考虑把数组开两倍。但是看到样例二,手动模拟一下,发现这不够,要三倍。
开始分析。显然, 位置能播放到的位置肯定<= 能放到的位置。比如这组数据:
15
58 37 28 74 28 41 50 34 72 79 45 42 94 54 39
我们计算每个位置能放到的位置,得到这样一个数组:
3 5 5 5 15 15 15 15 15 15 15 15 15 18 18
(小数据,可以手做做看或者模拟)
设这个数组为
。题目让我们求的就是
,并输出。设题目求的是
数组。
那么我们考虑求这个
。如果不是在“转折点”的时候,应该满足
。
所以我们现在就是要求这些转折点位置的答案。别的位置就直接
。
求转折点位置及答案
思考:为什么会有“转折”?
比如说第 个位置和第 个位置不一样。那么肯定是因为 位置更新了最大值,让最大值变大了,更加容易满足条件,所以答案减少。
能更新最大值的位置,就是转折点。我们用一个单调队列维护即珂(队列里面维护下标)。
入队列的条件
如果有一个元素A比另一个元素B排在后面,然后A还比B大,那么B无论如何也不会更新最大值了。因为,只要能考虑到B,就肯定能考虑到A,而且A还比你大。所以我们的队列,如果新的队尾大于原来的队尾,那么就弹出原来的队尾。换句话说,就是维护一个单调递减的队列。
出队列的条件
如果当前考虑的 ,满足 两倍小于队首 ,那么如果从 开始播放,肯定播放到 就停止了,后面就不会再有影响。所以如果发生了这样的情况,就记录队首的答案,并且把它弹出去。
转折点篇 完
代码
#include <bits/stdc++.h>using namespace std;
namespace Flandre_Scarlet
{
#define N 355555
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define p_b push_back
#define sz(a) ((int)a.size())
#define iter(a,p) (a.begin()+p)
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
int n,a[N];
void Input()
{
R1(n);F(i,1,n) R1(a[i]),a[i+n]=a[i+2*n]=a[i];
}
int Q[N],head,tail;
int ans[N];
void Soviet()
{
int Max=*max_element(a+1,a+n+1),Min=*min_element(a+1,a+n+1);
if (Min*2>=Max)
{
F(i,1,n) printf("-1%c"," \n"[i==n]);
return;
}//特判-1
head=0,tail=1;
F(i,1,3*n)
{
while(head<=tail and a[Q[tail]]<a[i]) --tail;
Q[++tail]=i; //入队列
while(head<=tail and a[Q[head]]>2*a[i])
{
ans[Q[head]]=i-Q[head]; //到i为止,但是题目要求输出的是pos[i]-i,所以干脆直接令答案为i-Q[head]
++head;
}
}
D(i,3*n,1)
{
if (ans[i]==0) ans[i]=ans[i+1]+1; //直接继承
}
F(i,1,n) printf("%d\n",ans[i]);
}
#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main(){
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}