Feel Good@POJ 2796

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

题意:给你一个非负整数数组,定义某个区间的参考值为:区间所有元素的和乘以区间最小元素。求该数组中的最大参考值以及对应的区间。
比如说有6个数3 1 6 4 5 2
最大参考值为6,4,5组成的区间,区间最小值为4,参考值为4*(6+5+4)=60
数据范围1<=n<=100000;

题目分析:理解题意后,会发现也是一个典型的单调栈问题。只不过这个在枚举每一个点的时候还要顺带求出每个点对应的区间合,这样时间复杂度就上升到了O(N^2),显然会TLE。所以处理这个问题的关键点就在于有效的降低求区间和时的时间复杂度。

我的解决方法是:定义两个数组sum_l 和 sum_r,sum_l[i] 、sum_r[i]分别表示以i点为间断点时i点左端区间合和(包含i)和i点右端区间和(包含i),这样 i 点对应的区间和就是 sum_l[i] + sum_r[i] - a[i]。以求左端区间和为例,求法是在单调栈弹栈的过程中实现的,当弹出顶点时,同时将 sum_l[i] 加上 sum_l[s.top()],这样做的解释就是只要你的值比我大,那么你左端区间包含的各个点的值肯定都比我大,我直接加上你左端区间和就行了,顺带把你左端区间包含的点也收纳到我的左端区间里。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cstdio>
#include <stack>
#include <deque>
#include <set>
#include <cmath>
#include <map>
#define MAXN 100004
#define INF 0x3f3f3f3f
using namespace std;

int l[MAXN];
long long sum_l[MAXN];
long long sum_r[MAXN];
int r[MAXN];
int a[MAXN];
stack<int> s;
int n;

void left_min(){
    while(!s.empty()) s.pop();
    for(int i=0;i<n;++i){
        while(!s.empty() && a[i] <= a[s.top()]){
            sum_l[i] += sum_l[s.top()]; //弹栈的同时直接加和
            s.pop();
        }
        if(!s.empty()) l[i] = s.top();
        else l[i] = -1;
        s.push(i);
    }
}

void right_min(){
    while(!s.empty()) s.pop();
    for(int i=n-1;i>=0;--i){
        while(!s.empty() && a[i] <= a[s.top()]){
            sum_r[i] += sum_r[s.top()];
            s.pop();
        }
        if(!s.empty()) r[i] = s.top();
        else r[i] = n;
        s.push(i);
    }
}

int main(){
    while(~scanf("%d",&n)){
        for(int i=0;i<n;++i){
            scanf("%d",&a[i]);
            sum_l[i] = sum_r[i] = a[i]; //初始化
        }
        left_min();
        right_min();
        long long ans = -1;
        int L,R;
        for(int i=0;i<n;++i){
            if((sum_l[i]+sum_r[i]-a[i])*a[i] > ans){
                ans = (sum_l[i]+sum_r[i]-a[i])*a[i]; //i点对应的区间和
                L = l[i]+1+1;
                R = r[i];
            }
        }
        cout << ans << endl;
        cout << L << ' ' << R << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39021458/article/details/81353825