题目大意:
有一群小熊站成一排,每只小熊都有一定的身高,定义连续的几只小熊(可以只有1只)称作group。每个group的长度为小熊的数量,强度为该区间最矮的那只熊的身高。
现在要你求出长度分别为1到n的所有group的最大强度。
(题目大意描述的有点不清楚,建议直接看题目)
大致思路:
一开始看到这道题目以为是线段树,事实上的确有不少人用线段树过了,奈何自己线段树太弱,所以没写出来。直到学习单调栈之后才发现这道题可以用单调栈过,复杂度也只有O(n)。我们枚举每只小熊为最矮身高时向两边扩展能覆盖的最大区间,然后再处理一下就ok了。这里还要注意一点,我们枚举出所有区间之后有可能会有小区间的值反而比大区间的值要小的情况,这个时候就要继承较大区间的值。(也就是说满足区间长度从小到大单调递减)
示例代码:
//CF_305_D.cpp
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 2*100000 + 10;
const int INF = 0x7fffffff;
int n;
int a[maxn], s[maxn], L[maxn], R[maxn], f[maxn];
void solve()
{
int t = 0;
memset(s, 0, sizeof(s));
memset(f, 0, sizeof(f));
for( int i=0; i<n; ++i )
{
while( t>0 && a[i]<=a[s[t-1]] ) --t;
L[i] = t==0 ? 0 : (s[t-1] + 1);
s[t++] = i;
}
t = 0;
for( int i=n-1; i>=0; --i )
{
while( t>0 && a[i]<=a[s[t-1]] ) --t;
R[i] = t==0? n : s[t-1];
s[t++] = i;
}
for( int i=0; i<n; ++i )
{
f[R[i]-L[i]] = max(a[i], f[R[i]-L[i]]);
}
for( int i=n-1; i>=0; --i )
{
if( f[i]<f[i+1] )
{
f[i] = f[i+1];
}
}
}
int main()
{
while( ~scanf("%d", &n) )
{
for( int i=0; i<n; ++i )
{
scanf("%d", &a[i]);
}
solve();
for( int i=1; i<=n-1; ++i )
{
printf("%d ", f[i]);
}
printf("%d\n", f[n]);
}
return 0;
}