CodeForces 547B(单调栈)

题目地址: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]);

}


posted on 2017-07-24 18:24  ljbguanli  阅读(285)  评论(0编辑  收藏  举报