题目链接:
题目大意:
给
n
个数,令
数据范围:
1≤n≤1e50≤ai≤106
解题思路:
这里就直接说单调栈了。
对于一个位置
i
,以
举个栗子,
{3,5,4,2,4,3,1}
,再来个图,这样比较形象:
以
2
为最小值,它的延伸区间就是
对于这个样例:
ihLR1313252234234216545563567117
有了这些,再用一个前缀和,就可以 O(n) 出解了!
栈,是个好东西!
详见代码:
//单调栈处理左右延伸区间
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <stack>
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const LL INF = 1LL << 60;
const int MaxN = 1e5;
int n;
int top;
LL h[MaxN + 5];
LL sum[MaxN + 5]; //前缀和
int L[MaxN + 5]; //L[i]表示以h[i]为最小值,向左延伸的最远位置
int R[MaxN + 5]; //R[i]则表示向右延伸的最远位置
int st[MaxN + 5];
void Init() {
for(int i = 1; i <= n; i++) scanf("%lld", &h[i]);
for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + h[i];
for(int i = 1; i <= n; i++) L[i] = R[i] = i;
}
void get_LR() {
int top = 1; //计算L
for(int i = 1; i <= n; i++) {
while(top > 1 && h[st[top - 1]] >= h[i])
top--;
if(top == 1) L[i] = 1;
else L[i] = st[top - 1] + 1;
st[top++] = i;
}
top = 1; //计算R
for(int i = n; i >= 1; i--) {
while(top > 1 && h[st[top - 1]] >= h[i])
top--;
if(top == 1) R[i] = n;
else R[i] = st[top - 1] - 1;
st[top++] = i;
}
}
void debug() {
for(int i = 1; i <= n; i++)
printf("%d ", L[i]);
printf("\n");
for(int i = 1; i <= n; i++)
printf("%d ", R[i]);
printf("\n\n");
}
int main()
{
while(scanf("%d", &n) != EOF)
{
Init();
get_LR();
//debug();
LL ans = -1;
int l = 0, r = 0;
for(int i = 1; i <= n; i++) {
LL x = (sum[R[i]] - sum[L[i] - 1]) * h[i];
if(x > ans) {
ans = x;
l = L[i];
r = R[i];
}
}
printf("%lld\n", ans);
printf("%d %d\n", l, r);
}
return 0;
}