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]); }