1. 程式人生 > >Codeforces Round #305 (Div. 1) B. Mike and Feet(單調棧)

Codeforces Round #305 (Div. 1) B. Mike and Feet(單調棧)

題意:給定一個長度為n(n<=2e5)的陣列,分別求出長度為(1~n)的所有區間的最小數的最大值。

思路:ans[i]表示長度為i區間的答案,我們可以知道如果i<j,那麼ans[i]>=ans[j],所以可以用長度大的區間答案去更新長度小的,所以對於每個元素,只要找到他能覆蓋的最大區間長度,然後只更新這個長度的答案即可,最後再整體用長度大的更新小的一次。求每個元素他能貢獻的最大的長度可以用單調棧。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+5;
int a[maxn], ans[maxn], n;
int minl[maxn], minr[maxn];

int main(void)
{
    while(cin >> n)
    {
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        memset(ans, 0, sizeof(ans));
        stack<int> s;
        while(!s.empty()) s.pop();
        for(int i = 1; i <= n; i++)
        {
            while(s.size() && a[s.top()] >= a[i]) s.pop();
            minl[i] = s.size()==0 ? 1 : (s.top()+1);
            s.push(i);
        }
        while(!s.empty()) s.pop();
        for(int i = n; i >= 1; i--)
        {
            while(s.size() && a[s.top()] >= a[i]) s.pop();
            minr[i] = s.size()==0 ? n : (s.top()-1);
            s.push(i);
        }
        for(int i = 1; i <= n; i++)
        {
            int len = minr[i]-minl[i]+1;
            ans[len] = max(ans[len], a[i]);
        }
        for(int i = n-1; i >= 1; i--)
            ans[i] = max(ans[i], ans[i+1]);
        for(int i = 1; i <= n; i++)
            printf("%d%c", ans[i], i==n ? '\n' : ' ');
    }
    return 0;
}