POJ - 2796(单调栈)

2019 GDUT Winter Training V ( 算法优化) C - Feel Good

poj传送门

专题传送门

题目大意:

给出一组数字,求一区间,使得区间元素和乘以区间最小值最大,结果要求给出这个最大值和区间的左右端点。

题目分析:

用一个单调递减栈,如果栈为空或入栈元素大于等于栈顶元素,则入栈,否则将破坏栈的单调性,则将栈顶元素出栈,直到栈为空或碰到第一个大于等于入栈元素的元素。然后将最后一次出栈的栈顶元素入栈,并将其像左右拓展,并更新其对应的值。
由于维护单调栈会改变原数组的值,同时为了方便求区间元素值,我们设置一个sum数组,记录前缀和。
我们将原数组的最后一个值设为最小值,以方便最后将栈内所有元素出栈。
注意:最后一次出栈的栈顶元素就是当前入栈元素可以向左拓展到的最大距离。

例如

我们要维护一个单调递增的栈,给出一组数11,4,8,5,13。我们模拟一下入栈过程,则如果入栈元素值小于栈顶元素值或者栈为空,则入栈;否则,则需要把比入栈元素小的元素全部出栈,因为如果入栈则会破坏栈的单调性。单调递减的栈反之。

11入栈时,栈为空,直接入栈,栈内元素为14。

4入栈时,栈顶元素11比4大,则入栈,栈内元素为11,4。

8入栈时,栈顶元素4比8小,则栈顶元素出栈,此时栈顶元素为11,比8大,则入栈,栈内元素为11,8。

5入栈时,栈顶元素8比5大,则入栈,栈内元素为11,8,5。

13入栈时,栈顶元素5比13小,5出栈,此时栈顶元素为8,仍比13小,栈顶元素8继续出栈,此时栈顶元素为11,仍比13小,11出栈,此时栈为空,13入栈,栈内元素为13。

这里给出伪代码

/*
* 本伪代码对应的是单调递减栈 
*共n个元素,编号为0~n-1
*/
while(栈为空) 栈顶元素出栈; //先清空栈
a[n]=-1;
for(i=0;i<=n;i++)
{
	if(栈为空或入栈元素大于等于栈顶元素) 入栈;
	else 
	{
		while(栈非空并且栈顶元素大于等于入栈元素)
		{
			栈顶元素出栈;
			更新结果; 
		} 
		将最后一次出栈的栈顶元素(即当前元素可以拓展到的位置)入栈; 
		更新最后一次出栈的栈顶元素其对应的值; 
	} 	 
}

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#define ll long long
using namespace std;
const int maxn = 1e5+5;
int emo[maxn];
ll sum[maxn];
stack<int> s;
int main(){
	int days;cin>>days;
	for(int i=1;i<=days;i++){
		scanf("%d",&emo[i]);
		sum[i]=sum[i-1]+emo[i];
	}
	emo[days+1]=-1;
	ll maxemo=-1;
	int pos1,pos2,fir;
	for(int i=1;i<=days+1;i++){
		if(s.empty()||emo[s.top()]<=emo[i]) s.push(i);
		else{
			while(!s.empty()&&emo[s.top()]>emo[i]){
				fir=s.top();s.pop();
				ll	tmp=sum[i-1]-sum[fir-1];
				tmp*=emo[fir];
				if(tmp>maxemo){
					maxemo=tmp;
					pos1=fir;
					pos2=i;
				}
			}
			s.push(fir);
			emo[fir]=emo[i];
		} 
	}
	printf("%lld\n",maxemo);
	printf("%d %d\n",pos1,pos2-1);
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值