!HDU 1506 Largest Rectangle in a Histogram-dp|单调队列-(dp降低时间复杂度)

题意:有宽度相同高度不同的长方体挨着放在一起,求能构成的面积最大的长方体

分析:也是思维的转换。这题的主思路不是dp,dp只是起一个辅助作用。具体做法:枚举每个长方体,求以这个长方体的高度为高的最大的长方体面积,不断更新答案。用一个l[i]r[i]数组表示第i个矩形的左右比它高的远的位置,所以面积 s=a[i]*(r[i]-l[i]+1).但是直接两重循环会超时,这时用了一点dp的思想,这里用的不是dp递推的思想,而是dp保存中间结果降低时间复杂度的思想。虽然也是两重循环,但是由于dp[]的关系,就跳过了很多重复的比较步骤。

注意积累这题的主思路,还有dp的用法。

我这几天学单调队列的时候发现这题也能用单调队列做,很简单:一个单增队列,依次遍历0~n-1的方块的高度放进队列,新增的元素A就是被它迫使出队的元素B的最远的高于B的方块右边那块,所以r[B]=A-1;左边界同理。O(n)就搞定了。注意初始化r[i]=n-1,L[i]=0,因为元素的L[],r[]值是在这个元素被迫出队时才更新的,有些元素的左右边界是0,n-1,它不会出队,如果不自己给它设置好,在维护队列的时候又不会更新,就会出错。

dp代码:

#include<iostream>
#include<cstring>
using namespace std;
long long n,a[100005];
long long mx,sum;
int l[100005],r[100005];
long long max(long long i,long long j)
{
	return i>j?i:j;
}
void DP()
{
	mx=0;
	for(int i=0;i<n;i++) l[i]=i,r[i]=i;
	for(int i=1;i<n;i++){
		int t=i;
		while(t>0&&a[t-1]>=a[i])
		   t=l[t-1];
		l[i]=t;
	}
	for(int i=n-2;i>=0;i--){
		int t=i;
		while(t<n-1&&a[i]<=a[t+1]) 
		   t=r[t+1];
		r[i]=t;
	}
	for(int i=0;i<n;i++){
		sum=a[i]*(r[i]-l[i]+1);
		mx=max(sum,mx);
 	}
}
int main()
{
	while(cin>>n){
		if(!n) break;
		for(int i=0;i<n;i++) cin>>a[i];
		DP();
		cout<<mx<<endl;
	}
}

单调队列代码:

#include<iostream>
#define max(a,b) a>b?a:b
using namespace std;
int n;
long long a[100010],q[100010],ans;
int l[100010],r[100010];
int main()
{
	while(cin>>n){
		if(!n) break;
		int head=0,rear=-1;
		ans=-1;
		for(int i=0;i<n;i++) cin>>a[i];
		for(int i=0;i<n;i++) r[i]=n-1,l[i]=0;
		for(int i=0;i<n;i++){
			while(head<=rear&&a[q[rear]]>a[i]){
				r[q[rear]]=i-1;
		        rear--;
			}			  
	        q[++rear]=i;
		}
		head=0,rear=-1;
		for(int i=n-1;i>=0;i--){
			while(head<=rear&&a[q[rear]]>a[i]){
				l[q[rear--]]=i+1;
			}
			q[++rear]=i;
		}
		for(int i=0;i<n;i++){
			long long tmp=(r[i]-l[i]+1)*a[i];
			ans=max(ans,tmp);		
		}
		cout<<ans<<endl;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值