CodeForces

CodeForces - 1237D Balanced Playlist 单调队列

题意

(n)首歌循环播放。每首歌都有欢乐值。

播到某首歌时,如果这首歌的欢乐值小于当前播放过的歌曲的最大值的一半(不四舍五入),则停止。

对于每首歌,求出这首歌开始能播放多少首歌曲。

[2leq n leq 10^5 \ 1leq a_i leq 10^9 ]

如果这首歌会播放无穷次,输出(-1)

分析

显然,输出-1的充要条件是当欢乐值最小的歌曲的两倍小于欢乐值最大的歌曲

剩下的都是可行解。

很容易想到此题会涉及到连续的区间的最值。有点类似移动窗口问题。

考虑到如果维护出一个单调递减的队列,如果读入的欢乐值的两倍比队首的欢乐值还小,显然这个时候队首就会在这里结束播放,弹出。

注意到这个此题就做完了。

注意的细节

  • 不能真的去算除以2,这样一想还不如用乘去代替
  • 数组要开三倍空间。因为首先是循环播放,其次是会因为有可能要跑一圈才能遍历所有情况。
  • 记录答案数组的时候有可能一些数组不会被更新到,这个时候只需要递推一遍即可。

代码

int a[maxn * 3];
int ans[maxn * 3];
int main() {
    int mx = -1;
    int mi = INF;
    int n = readint();
    for (int i = 0; i < n; i++)
        a[i] = readint(), mx = max(mx, a[i]), mi = min(mi, a[i]), a[i + n] = a[i + 2 * n] = a[i];
    if (mi * 2 >= mx) {
        for (int i = 0; i < n; i++)
            printf("-1 ");
        return 0;
    }
    deque<int> q;
    for (int i = 0; i < 3 *  n; i++) {
        while (!q.empty() && a[q.back()] < a[i]) q.pop_back();
        q.push_back(i);
        while (a[q.front()] > 2 * a[i]) {
            ans[q.front()] = i - q.front();
            q.pop_front();
        }
    }
    for (int i = 3 * n - 1; i >= 0; i--) 
        if (!ans[i]) ans[i] = ans[i + 1] + 1;
    for (int i = 0; i < n; i++)
        printf("%d ", ans[i]);
}
原文地址:https://www.cnblogs.com/hznumqf/p/13788397.html