题意:给一个数组,计算某段区间的和乘以该区间最小值,要求该值最大并输出区间范围。
思路:用一个单调栈,计算以某数为区间的最小值的区间左右范围。具体来说,如果栈顶为空则left[i]=1;如果非空,比较a[i]与栈顶元素的大小,如果a[i]小于栈顶则right[sk.top()]=i+1(我的区间表示是左闭右开)并弹出,如果相等则left[i]=left[sk.top()],如果大于则left[i]=sk.top()+1。再将当前值i压入栈中。最后,如果栈非空则计算弹出栈顶元素令right[sk.top()]=n+1。有了左右范围就可以直接枚举每个a[i]然后取最大值维护相应区间就行了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<iostream>
#define LL long long
using namespace std;
const int maxn=1000005;
int l[maxn],r[maxn];
int a[maxn];
LL sum[maxn];
int n;
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1; i<=n; ++i)
scanf("%d",&a[i]);
stack<int> sk;
for(int i=1; i<=n; ++i)
{
while(!sk.empty()&&a[sk.top()]>a[i])
{
r[sk.top()]=i;
sk.pop();
}
if(sk.empty()) l[i]=1;
else if(a[sk.top()]==a[i]) l[i]=l[sk.top()];
else l[i]=sk.top()+1;
sk.push(i);
}
while(!sk.empty())
{
r[sk.top()]=n+1;
sk.pop();
}
for(int i=1; i<=n; ++i)
sum[i]=sum[i-1]+a[i];
LL now=0,best=-1;
int now_l,now_r;
int best_l,best_r;
for(int i=1; i<=n; ++i)
{
now=(sum[r[i]-1]-sum[l[i]-1])*a[i];
if(now>best)
{
best=now;
best_l=l[i];
best_r=r[i];
}
else if(now==best)
{
if(r[i]-l[i]<best_r-best_l)
{
best_l=l[i];
best_r=r[i];
}
}
}
printf("%lld\n",best);
printf("%d %d\n",best_l,best_r-1);
}
return 0;
}