CodeForces - 1237D Balanced Playlist 單調佇列
阿新 • • 發佈:2020-10-09
CodeForces - 1237D Balanced Playlist 單調佇列
題意
\(n\)首歌迴圈播放。每首歌都有歡樂值。
播到某首歌時,如果這首歌的歡樂值小於當前播放過的歌曲的最大值的一半(不四捨五入),則停止。
對於每首歌,求出這首歌開始能播放多少首歌曲。
\[2\leq n \leq 10^5 \\ 1\leq 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]); }