题意: 给你n个数字 定义一个区间的值为(区间内所有值的和)*(区间内的最小值)
求所有合法区间中的最大值 并输出区间和最大值。
思路:枚举最小值,然后利用单调栈,求出每个位置的一直大于他的左端点和右端点,然后利用前缀和求值。
#include <iostream>
#include <cstdio>
#include <set>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#include <string>
#include <cctype>
using namespace std;
typedef __int64 LL;
const int maxn = 1e6+10;
LL h[maxn];
LL st[maxn];
LL l[maxn];
LL r[maxn];
LL pre[maxn];
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%I64d",&h[i]);
memset(pre,0,sizeof(pre));
LL top;
h[0]=h[n+1]=-1;
st[top=1]=0;
for(int i=1; i<=n; i++)
{
while(h[i]<=h[st[top]])
top--;
l[i]=st[top];
st[++top]=i;
}
st[top=1]=n+1;
for(int i=n; i>=1; i--)
{
while(h[i]<=h[st[top]])
top--;
r[i]=st[top];
st[++top]=i;
}
for(int i=1; i<=n; i++)
{
pre[i]+=pre[i-1]+h[i];
}
LL sum=-1;
LL ll,rr;
for(int i=1; i<=n; i++)
{
LL x=(pre[r[i]-1]-pre[l[i]])*h[i];
if(x>sum)
{
sum=x;
ll=l[i]+1;
rr=r[i]-1;
}
}
printf("%I64d\n",sum);
printf("%I64d %I64d\n",ll,rr);
}
return 0;
}