POJ2796/DP/单调栈

题目链接[http://poj.org/problem?id=2796]

题意:给出一个数列,要求在这个数列里找到一个区间,使得在这个区间里的最小值*SUM[l,r]最大。

题解:思路来源于【http://acm.hdu.edu.cn/showproblem.php?pid=1506】这个题。思想是:一a[i]为某个区间的最小值,初始区间为[i,i],左端向左延伸,右端向右延伸。最后维护最大值。

但是向前向后延伸的时候不能暴力,时间不允许,这里要用到DP的思想:

定义L[MAXN]=R[MAXN]=i;对于a[i]的L[i],刚开始的L[i]=i;如果a[i]>a[L[i]-1] -> L[i]=L[L[i]-1];2、R同理。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 100050;
LL a[MAXN], sum[MAXN];
LL L[MAXN], R[MAXN];
int n;
int main ()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
        sum[i] = sum[i - 1] + a[i];
        L[i] = R[i] = i;
    }
    a[0] = a[n + 1] = -1;//保证不会访问或者访问无效。
    for(int i = 1; i <= n; i++)
    {
        while(a[i] <= a[L[i] - 1])
            L[i] = L[L[i] - 1];
    }
    for(int i = n; i >= 1; i--)
    {
        while(a[i] <= a[R[i] + 1])
            R[i] = R[R[i] + 1];
    }
    LL ans = -1, l, r;
    for(int i = 1; i <= n; i++)
    {
        LL T = a[i] * (sum[R[i]] - sum[L[i] - 1]);
        if(ans < T)
            ans = T, l = L[i], r = R[i];
    }
    printf("%lld\n%lld %lld\n", ans, l, r);
}

 

posted @ 2017-01-10 20:00  _Mickey  阅读(1274)  评论(0编辑  收藏  举报