题意:
有n首音乐,每首音乐都有一个值ai,从第i首开始,列表循环播放,当前播放的所有音乐中的最大值计为mx,如果下一首音乐的值*2 < mx,那么,终止播放。
问:依次从每一首开始播放,各可以播放几首?
思路:
这题我是看了题解才会的,果然还是菜呀。
对于i,我们找1~(i-1)中,最靠近 i 的 j ,使得ai * 2 < aj,这一步用单调队列+二分来做。
找到 j 以后,就可以更新 j 的答案了,用min,就是看 如果从 j 开始的话(mx就是为aj ,先不考虑 j 后面的点)最快到哪里会停下。
但是mx是会变的,所以从后扫回来,min一下。
结束。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #include <cmath> #include <iostream> #include <vector> #include <algorithm> using namespace std; typedef long long int ll; const double pi = acos(-1); const int maxn = 3e5 + 10; const int inf = 0x3f3f3f3f; int qu[maxn],a[maxn],n,mi[maxn],head,tail,ans[maxn]; void _push(int pos) { while(head <= tail && a[pos] >= a[qu[tail]]){ tail--; } qu[++tail] = pos; } int get_pos(int u) { int l = head,r = tail,mid,res = -1; while(l <= r){ mid = (l + r) >> 1; if(a[qu[mid]] > a[u] * 2){ res = mid; l = mid + 1; } else r = mid - 1; } if(res == -1) return -1; return qu[res]; } int main() { while(scanf("%d",&n) != EOF){ head = 0; tail = -1; memset(mi,inf,sizeof(mi)); int _mi = 1e9,_mx = 0; for(int i = 1;i <= n;i++){ scanf("%d",&a[i]); _mi = min(_mi,a[i]); _mx = max(_mx,a[i]); a[n + i] = a[2 * n + i] = a[i]; } n = 3 * n; if(!(_mx > _mi * 2)){ for(int i = 1;i <= n / 3;i++) printf("-1 "); puts(""); continue; } int temp; for(int i = 1;i <= n;i++){ _push(i); temp = get_pos(i); if(temp == -1) continue; mi[temp] = min(mi[temp],i); } _mi = 1e9; int res; for(int i = n;i >= 1;i--){ res = min(_mi,mi[i]); ans[i] = res; _mi = min(_mi,mi[i]); } for(int i = 1;i <= n / 3;i++) printf("%d ",ans[i] - i); puts(""); } return 0; }