Gym - 101334F Feel Good(单调栈模板题 或者用线段树做)*

博客介绍了Codeforces Gym的一道题目,要求找出一串数中,某连续子序列的值等于该序列总和乘以最小值的最大可能值。作者提供了单调栈的解决方案,强调了在代码中设置a[n+1] = -1作为边界条件的重要性。线段树解法目前尚未更新。
摘要由CSDN通过智能技术生成
链接:http://codeforces.com/gym/101334
题目大意:

给你n个数,某个连续区域的值为 该区域的总和 乘以 区域最小值 ,求出这n个数中区域值最大 ,并输出,并输出该区域由第几个数到第几个数(include)

分析:

单调栈模板题:

单调栈 代码:

这里有个注意的地方就是a[n+1]赋值为-1(小于0就行),ans也初始为-1

// #include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <stack>
#include <cstring>
using namespace std;
#define ll long long
#define p pair<ll , ll>

const int N=1e5+100;;
ll lef[N]; // left[x]以a[x]为矩形的最小的高度的的区域的最左边所在的位置
ll right[N]; // right[x] 表示以a[x]为矩形的最小的高度的的区域的最右边所在的位置


stack<p> sta; // p a的一个数存数据大小,后一个数表示是第几个数

ll a[N];//存放数据
ll sum[N];

ll solve(int n,int& st,int& ed)
{
	ll ans=-1;
	for(int i=1;i<=n+1;i++)//这里为什么要+1呢,是为了栈中元素都弹出来
	{
		if(sta.empty())  //若为空,压入栈
		{
			sta.push(make_pair(a[i],i));
			lef[i]=i; //最左边就是自己本身
		}
		else if(a[i]>sta.top().first)
		{
			sta.push(make_pair(a[i],i));
			lef[i]=i;//因此栈中的都是比a[i]小的,故最左边就是自己本身
		}
		else
		{
			int t=i;
			while(!sta.empty()&&sta.top().first>a[i])
			{
				//说明此时sta.top()要弹出,a[i]就是它的最右的边界(不包含a[i]这个数)
				// 当然这里可以用right[i]数组先存起来,可能有的题目需要用上
				t=lef[sta.top().second];// 用来标记以a[i] 为最低高度的局域的 最左边所在的位置
				// cout<<"ans,top,lef[i]"<<ans<<" "<<sta.top().first<<" "<<lef[sta.top().second]<<" "<<t<<endl;
				// ans=max(ans,(sta.top().first)*(sum[i-1]-sum[ lef[sta.top().second]-1]));
				if((sta.top().first)*(sum[i-1]-sum[ lef[sta.top().second]-1])>ans)
				{
					ans=(sta.top().first)*(sum[i-1]-sum[ lef[sta.top().second]-1]);
					st=lef[sta.top().second];
					ed=i-1;
				}
				// cout<<"i="<<i<<" "<<ans<<endl;
				// left[sta.top().second] 表示sta.top()最左的边界  
				// (i-left[sta.top().second] 表示的是以sta.top().first为最低高度的局域的 矩形的个数
				sta.pop();
			}
			sta.push(make_pair(a[i],i));
			lef[i]=t;
			
			
		}
	// cout<<"i,lef="<<i<<" "<<lef[i]<<endl;
	}
	return ans;
}


int main()
{
	freopen("feelgood.in","r",stdin);
	freopen("feelgood.out","w",stdout);
	int n;
	while(~scanf("%d",&n))
	{
		sum[0]=0;
		
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			sum[i]=sum[i-1]+a[i];
		}
		a[n+1]=-1;
		while(!sta.empty())
			sta.pop();
		int st,ed;
		ll ans=solve(n,st,ed);
		printf("%lld\n",ans);
		
		printf("%d %d\n",st,ed);
		
	}
	
	return 0;
}
线段树代码:(待更新)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值