题目链接:https://vjudge.net/problem/CodeForces-547B
题意:给出n个数,要求求出所有规模大小为1-n的连续子串中的strength的最大值,strength为一个子串中的最小的那个数值
解题思路:
L[i]表示第i个元素的最左边作用范围(左边界)
R[i]表示第i个元素的最右边作用范围(右边界)
如:1 2 3 4 3 2 1 L[4]=3; R[4]=5; L[1]=0; R[1]=n+1=8;
利用的是单调栈(单增)进行处理
分两次分别处理L和R
L处理步骤:从前往后进行入栈,栈中存入下标,1 -> 1 2 -> 1 2 3 -> 1 2 3 4 ->1 2 3 -> 1 2 -> 1
R处理步骤:从后往前进行入栈…
s1.push(1); L[1]=0;
for(int i=2;i<=n;i++){
while(!s1.empty()&&a[s1.top()]>=a[i])
s1.pop();
if(s1.empty())
L[i]=0;
else
L[i]=s1.top();
s1.push(i);
}
s2.push(n); R[n]=n+1;
for(int i=n-1;i>=1;i--){
while(!s2.empty()&&a[s2.top()]>=a[i])
s2.pop();
if(s2.empty())
R[i]=n+1;
else
R[i]=s2.top();
s2.push(i);
}
处理完L和R数组后,进行ans的计算,
以第i个元素为例,它的作用范围为L[i]+1到R[i]-1,所以该长度为len=R[i]-L[i]-1的最小值一定是a[i]
for(int i=1;i<=n;i++){
int len=R[i]-L[i]-1;
ans[len]=max(ans[len],a[i]);
}
如果一个元素的作用域为len,那么以他为中心的长度为1,2,… ,len的ans最小值都应该是a[i]
for(int i=n-1;i>=1;i--)
ans[i]=max(ans[i+1],ans[i]);
代码如下:
#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
int n;
int a[210000];
int L[210000],R[210000];
int ans[210000];
stack<int> s1,s2;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
s1.push(1); L[1]=0;
for(int i=2;i<=n;i++){
while(!s1.empty()&&a[s1.top()]>=a[i])
s1.pop();
if(s1.empty())
L[i]=0;
else
L[i]=s1.top();
s1.push(i);
}
s2.push(n); R[n]=n+1;
for(int i=n-1;i>=1;i--){
while(!s2.empty()&&a[s2.top()]>=a[i])
s2.pop();
if(s2.empty())
R[i]=n+1;
else
R[i]=s2.top();
s2.push(i);
}
for(int i=1;i<=n;i++){
int len=R[i]-L[i]-1;
ans[len]=max(ans[len],a[i]);
}
for(int i=n-1;i>=1;i--)
ans[i]=max(ans[i+1],ans[i]);
for(int i=1;i<=n;i++)
if(i!=n)
printf("%d ",ans[i]);
else
printf("%d\n",ans[i]);
return 0;
}