poj2796Feel Good(单调栈)

Feel Good
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 13572   Accepted: 3796
Case Time Limit: 1000MS   Special Judge

Description

Bill is developing a new mathematical theory for human emotions. His recent investigations are dedicated to studying how good or bad days influent people's memories about some period of life. 

A new idea Bill has recently developed assigns a non-negative integer value to each day of human life. 

Bill calls this value the emotional value of the day. The greater the emotional value is, the better the daywas. Bill suggests that the value of some period of human life is proportional to the sum of the emotional values of the days in the given period, multiplied by the smallest emotional value of the day in it. This schema reflects that good on average period can be greatly spoiled by one very bad day. 

Now Bill is planning to investigate his own life and find the period of his life that had the greatest value. Help him to do so. 

Input

The first line of the input contains n - the number of days of Bill's life he is planning to investigate(1 <= n <= 100 000). The rest of the file contains n integer numbers a1, a2, ... an ranging from 0 to 10 6 - the emotional values of the days. Numbers are separated by spaces and/or line breaks.

Output

Print the greatest value of some period of Bill's life in the first line. And on the second line print two numbers l and r such that the period from l-th to r-th day of Bill's life(inclusive) has the greatest possible value. If there are multiple periods with the greatest possible value,then print any one of them. 

Sample Input

6
3 1 6 4 5 2

Sample Output

60
3 5

Source

Northeastern Europe 2005

参考博客

题意:给你一段区间,需要你求出(在这段区间之内的最小值*这段区间所有元素之和)的最大值......

例如:

6
3 1 6 4 5 2

以4为最小值,向左右延伸,6 4 5  值为60.......


新学了单调栈,看完代码才懂了具体是怎么操作的。

单调栈的原理,它就是以某一个值为最小(最大)值,向这个值的两侧延伸,遇到大于它(小于它)的值,就将它延伸的范围扩大,当然,一般来说,要这样做的算法复杂度为o(n^2),但是借助栈这个玩意,维护其单调增(减),就可以在o(n)的时间复杂度解决这个问题。将一元素加入栈时,先判断它是否大于(小于)栈顶元素,若是大于(小于)栈顶元素,加入栈。(从这里开始只讲维护单调增栈)否则,将栈顶元素出栈,直到栈顶元素小于要加入栈的元素,在此过程中,需要维护向前延伸和向后延伸的问题,当要加入栈的元素之前有n个栈元素出栈,那么说明这n个出栈的元素都会大于或者等于要入栈的元素,此时,我们需要维护入栈元素可以向前延伸多少个元素(相当于记录它的前面有多少个元素比它大),而每个栈顶元素要向出栈了的元素延伸,因为在出栈了的元素一定是比它的大的元素(根据我维护的是单调增栈)......这样,就在o(n)的时间复杂度内解决了上述问题.........

例如:3 1 6 4 5 2

(3,1,1)  (1,2,2)  (6,3,3)  (4,4,4)  (5,5,5)  (2,6,6)

首先每个元素自己本身的前后延伸都为1,把3加入栈,1<3,把3出栈,用1的前延伸加上3的前延伸,如此变为(1,1,2),6<1,入栈,变成(1,1,2)(6,3,3),

4<6,将6出栈,4向前延伸,1向后延伸变成(1,1,3) (4,3,4) 

5>4,入栈,变成(1,1,3)(4,3,4)(5,5,5)

2<5,5出栈,2向前延伸,4向后延伸,变成(1,1,3)(4,3,5)                   2还未入栈(2,5,6)

2<4,4出栈,2向前延伸,1向后延伸,变成(1,1,5) (2,3,6).....

一次类推,会发现最大的结果在(4,3,5)这里这意味着,以4为最小值的区间范围为3————5,也就是6 4 5  

 

#include 
#include
#include
#include
using namespace std;
const int maxn=1e5+100;
typedef long long ll;
struct node{
    ll num;
    int pre,next,p;
    node(ll a=0,int d=0):num(a),pre(1),next(1),p(d) {}
};
ll sum[maxn];
ll a[maxn];
int main(int argc, const char * argv[]) {
    int n;
    scanf("%d",&n);
    sum[0]=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    stack s;
    node tmp=node(a[1],1);
    //cout << a[1];
    s.push(tmp);
    ll ans=-1;
    int p1=-1,p2=-1;
    for(int i=2;i<=n;i++)
    {
        node t=node(a[i],i);
        while(!s.empty()&&s.top().num>t.num)
        {
            node t1=s.top();
            s.pop();
            t.pre+=t1.pre;
            if(!s.empty())
                s.top().next+=t1.next;
            ll res=t1.num*(sum[t1.p+t1.next-1]-sum[t1.p-t1.pre]);//
            if(res>ans)
            {
                ans=res;
                p1=t1.p-t1.pre+1,p2=t1.p+t1.next-1;
            }
        }
        s.push(t);
        
    }
    while(!s.empty())
    {
        node t1=s.top();
        s.pop();
        if(!s.empty())
            s.top().next+=t1.next;
        ll res=t1.num*(sum[t1.p+t1.next-1]-sum[t1.p-t1.pre]);
        if(res>ans)
        {
            ans=res;
            p1=t1.p-t1.pre+1,p2=t1.p+t1.next-1;
        }
        
    }
    printf("%lld\n%d %d\n",ans,p1,p2);
    return 0;
}



你可能感兴趣的:(单调栈,数据结构)