poj2796

#include <cstdio>
/*
 *  source poj.2796
 *  题目: 
 *      给定一个非负数的数组 其中value[l,r] = sum(l,r) * min (l,r);
 *    求 最大值和,最大值的位置
 *  题解:
 *      所求的区域的最小值是x的话一定是这个值向左右去延伸至比他大的元素为止
 *   而这个问题的求解一般是n^2的问题,但是我们不能接受因此;
 *      维护这个区间需要我们维护一个stack
 *      具体操作如下
 *      (1)元素入栈
 *       1,记录值(value, weight) -> weight 初始是1,value是入栈的值,
 *       2,先让大于等于value的值出栈,并且更新 ANS  [value * weight]   对比决定是否更新.   
 *       3,如果这个栈顶元素也大于等于value, 把出栈的这个值的重量给目前的栈顶元素, 到步骤(2),否则到步骤(4).
 *       4,把这个出栈的重量给 准备入栈的元素.
 *       5,元素入栈
 *   (2)元素全部入栈后 因为还有元素在里面. 剩下的元素逐个出栈,  只不过把这个元素的重量给下一个栈顶元素. 类似与插入-1.
 *       hint:
 *
 *     其实他每次出栈的 就是我们刚开说的那种区间, 以那个元素为做小值向左右扩展得到的区间值.
 *
 *     对于栈顶元素.
 *          一个元素的入栈 会促使 左侧比他大的合并,
 *               而后出栈的时候右侧肯定也都合并到自己身上,因此栈顶元素对于我们所扫描到的位置一定是合法的
 *      栈顶元素肯定向右或者说向左都是达标的;
 *      这是个斜率优化问题. 怀念以前,现在是个弱鸡(ง •̀_•́)ง        
 */
#define min(x, y) ( (x) < (y) ? (x) : (y) )
#define max(x, y) ( (x) < (y) ? (y) : (x) )
const int N = 1e5;
struct Ans {
    int l, r;
    long long value;
    Ans(){l = r = value = -1;}
    bool operator < (const  Ans & rht ) const {
        return value < rht.value;
    }
    void out(){
        printf("%lld\n%d %d\n", value, l, r);
    }
    void show(int i) {
        printf("i = %d %d %d %lld \n", i, l, r, value);
    }
};
struct Info {
    long long h, w;
    int p; 
    Info(){}
    Info(long long _h, long long  _w, int _p):h(_h), w(_w), p(_p) {}
    bool operator < (const Info & rht) const {
        return this -> h < rht.h;
    }
    Info operator + (const Info & rht) const {
        return Info( min(rht.h, this -> h), rht.w + this -> w, this -> p);
    }
};
Info stack[N + 7];
int pos;
Ans ans;
inline void init() {
    pos = 0;
    ans = Ans();
}
void in(long long tmp, int i) {
    Info inStack = Info(tmp, tmp, i);
    Info key = Info(0x7fffffff, 0, -1);
    while(pos != 0 && stack[pos - 1].h >= inStack.h) {
        key = stack[--pos] + key;
        Ans wps = Ans();
        wps.l       = key.p;
        wps.r       = i - 1;
        wps.value   = (long long )key.w * (long long )key.h;

        ans = max(ans, wps);
    }
    if (key.p != -1) {
        inStack = key + inStack;
    }
    stack[pos++] = inStack;
} 
int main() {
    int n;
    long long tmp;
    while(~scanf("%d", &n)) {
        init();
        for(int i = 1; i <= n; ++i) {
            scanf("%lld", &tmp);
            in(tmp, i);
        }
        in(0, n + 1);
        ans.out();   
    }
    return 0;
}

 

posted @ 2017-08-31 17:14  默默无语敲代码  阅读(217)  评论(0编辑  收藏  举报