题目地址:http://codeforces.com/problemset/problem/547/B
题意:有一个长度为n的序列,序列有长度为1...n的连续子序列,一个连续子序列里面最小的值称作这个子序列的子序列的strength,要求出每种长度的连续子序列的最大的strength。
做法:我们可以求出每一个数所在的一个区间,使得这个区间里面该数是最小的。那么,对于每个长度i(1<=i<=n),总有一个数所在的这种区间是i。那么对于一种长度为i的连续子序列,Strength就可以从这些数里面求出来。那么,问题是:如何求出一个数所在的区间使得那个数是最小的呢。答案就是单调栈。单调栈就是一个数字是单调的栈(单调递增或者单调递减)。在这道题,需要一个单调递增的单调栈。这样,我们可以求出那个区间的左端点和右端点,这样得到那个区间的长度。由于对于一个长度i,长度为i-1的子序列的最大的Strength肯定是大于等于长度为i的连续子序列的strength,所以假如一个数为num[i],所得的区间长度是len,那么先做标记ans[len]=max(ans[len],num[i]),然后对于所有数都标记完之后,对于ans数组从后往前递推ans[i]=max(ans[i],ans[i+1])。可以这样做是因为对于一个数,所在的区间长度为len,其实它所在的区间长度还可以是1...len,所以从后往前推是可以的。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <cstring>
#include <climits>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <utility>
#include <sstream>
#include <complex>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <functional>
#include <algorithm>
typedef long long LL;
using namespace std;
const int maxn=200005;
int sta[maxn];//用数组表示栈
int num[maxn],l[maxn],r[maxn];
int maxed[maxn];//maxed[i]是指长度为i的连续子序列的最大strength
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
} int ptr=1;
sta[1]=1;l[1]=0,r[1]=n+1;//l[i]代表一个数所在区间的左端点,r[i]代表右端点
for(int i=2;i<=n;i++)
{
while(ptr>=1&&num[i]<=num[sta[ptr]])//ptr是单调栈的栈顶下标
{
int cur=sta[ptr];
r[cur]=i;
ptr--;
}
if(ptr==0) l[i]=0;
else l[i]=sta[ptr];
sta[++ptr]=i;
r[i]=n+1;
}
for(int i=1;i<=n;i++) maxed[i]=-1;
int track=1;
for(int i=1;i<=n;i++)
{
int len=r[i]-l[i]-1;
maxed[len]=max(maxed[len],num[i]);
}
for(int i=n;i>=1;i--) maxed[i]=max(maxed[i+1],maxed[i]);
for(int i=1;i<=n;i++) printf("%d ",maxed[i]);
}