CodeForces - 548D Mike and Feet(单调栈)

题目链接:点击查看

题目大意:给出一个长度为 n 的数列,现在规定对于任意长度区间为 len 的答案为,所有长度为 len 的区间内的最小值的最大值,题目要求我们输出len为 1 ~ n 时的答案

题目分析:看似很复杂,其实我们只需要维护每个区间内的最小值就好了,并且顺便维护一下区间长度,如果暴力枚举每个区间显然是不行的,我们可以利用单调栈,求出每个数字左边和右边第一个比他小的数字的位置,那么由这两个位置组成的开区间内的最小值显然就是当前数字了,有了区间的两个端点区间长度也很容易计算了,O(n)计算出这些数据后,更新一下答案就好了,注意一下,因为并不是每个区间都能对应上答案的,所以最后我们还需要根据答案数组再从大到小更新一遍,因为显然如果 [ l , r ]的最小值为mmin,那么这段区间内的任意一段连续的子区间的最小值肯定不可能小于 mmin,可以利用这个性质更新没有涉及到的答案区间

代码:

#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
 
typedef long long LL;
 
const int inf=0x3f3f3f3f;
 
const int N=2e5+100;

int a[N],L[N],R[N],ans[N];

int main()
{
//	freopen("input.txt","r",stdin);
//	ios::sync_with_stdio(false);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	stackst;
	for(int i=1;i<=n;i++)
	{
		while(st.size()&&a[st.top()]>=a[i])
			st.pop();
		if(st.size())
			L[i]=st.top();
		else
			L[i]=0;
		st.push(i);
	}
 	while(st.size())
 		st.pop();
 	for(int i=n;i>=1;i--)
 	{
 		while(st.size()&&a[st.top()]>=a[i])
 			st.pop();
 		if(st.size())
 			R[i]=st.top();
 		else
 			R[i]=n+1;
 		st.push(i);
	}
	memset(ans,0,sizeof(ans));
	for(int i=1;i<=n;i++)
		ans[R[i]-L[i]-1]=max(ans[R[i]-L[i]-1],a[i]);
	for(int i=n-1;i>=1;i--)
		ans[i]=max(ans[i],ans[i+1]);
 	for(int i=1;i<=n;i++)
 		printf("%d ",ans[i]);
 
 
 
	
	
	
	
	
	
	
	
	
	return 0;
}

 

你可能感兴趣的:(单调栈/单调队列)