poj 2796#单调栈

参考:

对于这个问题,一般有两种方法:

1。枚举区间,找最小值一般复杂度太高不考虑

2。枚举点,找区间让每个点作为最低点。

对于思路二:

我们有如下的性质:

1. 如果当前元素大于前一元素,那么前一元素能扩展到当前元素,同时说明前面的数对当前元素来说是没有贡献的

2。如果当前元素等于前一元素,那么前一元素也能扩展到当前元素,同时说明前面的元素是可以被忽略的

3。如果当前元素小于前一个元素,那么前面至少有一个元素不能扩展到当前元素的位置,那么这些不能继续扩展的元素的存在显的没有什么意义了,不妨删除它。

我们得到两条结论:

1。一旦一个元素已经进入栈中那么这个元素向左扩展的位置就确定下来了.

2。一旦一个元素出栈被弹出栈,那么这个元素向右扩展的位置也确定下来了.



代码:

/*
单调栈
*/
#include <stdio.h>

#define N 100001

int a[N]
   ,lef[N]  //lef[i] 表示a[i]为最低点的左边界
   ,stack[N]
   ,top;
__int64 sum[N];

int main()
{
    __int64 ans = -1,tmp;
    int i,j,n;
    int ll,rr;
    scanf("%d",&n);
    for(i = 1; i <= n; ++i)
        scanf("%d",a + i),sum[i] = sum[i-1] + a[i];
    a[++n] = -1;
    for(i = 1; i <= n; ++i)
    {
        if(top == 0 || a[i] > a[stack[top-1]])
        {
            stack[top++] = i;
            lef[i] = i;
            continue;
        }

        if(a[i] == a[stack[top-1]])
            continue;
        while(top >= 1 && a[i] < a[stack[top-1]])
        {
            --top;
            tmp =  1LL * a[stack[top]] * (sum[i-1] - sum[lef[stack[top]]-1]);
            if(tmp > ans)
                ll = lef[stack[top]],rr = i - 1,ans = tmp;
        }
        lef[i] = lef[stack[top]];
        stack[top++] = i;
    }
    printf("%I64d\n%d %d\n",ans,ll,rr);
//    while(1);
    return 0;
}
/*

3
100000000 100000000 100000000

*/


阅读更多

没有更多推荐了,返回首页