链接: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;
}