【CCF 201312-3】最大的矩形(单调栈) & 【POJ 2823】Sliding Window(单调队列) Apare_xzc

最大的矩形(单调栈) & Sliding Window(单调队列)


今天刷CCF的时候碰到了最大的矩形这个题,顺便复习了一下单调栈和单调队列

Sliding Window

POJ 2823题目链接<–

题意:

   给一个1E6长的数列,求每个长度为K的区间的最大值和最小值
【CCF 201312-3】最大的矩形(单调栈) & 【POJ 2823】Sliding Window(单调队列) Apare_xzc_第1张图片

代码:

/*
POJ 2823 Sliding Window
Run ID	    User	Problem	 Result	    Memory	Time	Language	Code Length	 Submit Time
21072853	apare	2823	 Accepted	4016K	5516MS	C++	        1249B	     2019-11-20 14:03:59
21072236	apare	2823	 Time Limit Exceeded		C++	823B	             2019-11-20 11:26:56
单调队列,用deque TLE了,用数组模拟队列,5516MS过了 
*/
#include 
#include 
#include 
#include 
//#include 
using namespace std;
const int maxn = 1e6+100;
int a[maxn];
int Q[maxn];
int main()
{
     
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i)
	{
     
		scanf("%d",a+i);	
	}
/*	
	deque >Q; //pair
	for(int i=1;i<=n;++i)
	{  
		while(!Q.empty()&&a[i]<=Q.back().first) Q.pop_back();
		Q.push_back(make_pair(a[i],i));
		while(!Q.empty()&&Q.front().second<=Q.back().second-k) Q.pop_front();
		if(i>=k) printf("%d%c",Q.front().first,i==n?'\n':' ');	
	}
	Q.clear();
	for(int i=1;i<=n;++i)
	{  
		while(!Q.empty()&&a[i]>=Q.back().first) Q.pop_back();
		Q.push_back(make_pair(a[i],i));
		while(!Q.empty()&&Q.front().second<=Q.back().second-k) Q.pop_front();
		if(i>=k) printf("%d%c",Q.front().first,i==n?'\n':' ');	
	}
	return 0;
*/
	int pf = 0,pb = 0;
	for(int i=1;i<=n;++i)
	{
     
		while(pb>pf&&a[i]<=a[Q[pb-1]]) pb--;
		Q[pb++] = i;
		while(pb>pf&&Q[pf]<=Q[pb-1]-k) pf++;
		if(i>=k) printf("%d%c",a[Q[pf]],i==n?'\n':' ');
	} 
	pf = pb = 0;
	for(int i=1;i<=n;++i)
	{
     
		while(pb>pf&&a[i]>=a[Q[pb-1]]) pb--;
		Q[pb++] = i;
		while(pb>pf&&Q[pf]<=Q[pb-1]-k) pf++;
		if(i>=k) printf("%d%c",a[Q[pf]],i==n?'\n':' ');
	} 
	return 0;	
} 

最大的矩形

题意:求最大的矩形的面积

【CCF 201312-3】最大的矩形(单调栈) & 【POJ 2823】Sliding Window(单调队列) Apare_xzc_第2张图片
【CCF 201312-3】最大的矩形(单调栈) & 【POJ 2823】Sliding Window(单调队列) Apare_xzc_第3张图片

思路:

  • 求最大的矩形的面积,那么求高度为h[1],h[2],h[3]…到h[n]的最大的矩形面积的最大值
  • 那么我们要做的就是处理出每个高度h[i]左边和右边能拓展的长度(找到左右两边最远的高度>=h[i]的坐标L[i]和R[i])
  • 那么ans = max(ans, h[i]*(R[i]-L[i]+1))
  • 可以用单调栈维护:
    先把0入栈,然后从做到右和从右到左分别维护单调递增的栈
pos         0 1 2 3 4 5 6 
height      0 3 1 6 5 2 4  
     0
     0 3(0个)
     0 1(1个) 
     0 1 6
     0 1 5
     0 1 2
     0 1 2 4

代码

#include 
using namespace std;
int a[1005],L[1005],R[1005];
int main()
{
     
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",a+i);
	stack<pair<int,int> > st; //pair(value,pos)
	st.push(make_pair(0,0));
	for(int i=1;i<=n;++i)
	{
     
		while(!st.empty()&&st.top().first>=a[i]) st.pop();
		L[i] = st.top().second+1; 
		st.push(make_pair(a[i],i));
	}
	while(!st.empty()) st.pop();
	st.push(make_pair(0,n+1));
	for(int i=n;i>=1;--i)
	{
     
		while(!st.empty()&&st.top().first>=a[i]) st.pop();
		R[i] = st.top().second-1;
		st.push(make_pair(a[i],i));
	}
	int ans = 0;
	for(int i=1;i<=n;++i)
		ans = max(ans,a[i]*(R[i]-L[i]+1));
	printf("%d\n",ans);
	
	return 0;
}

你可能感兴趣的:(CCF,POJ,解题报告)