单调栈 poj2796

题目大意:给出n个数,求一个区间,使得这个区间的(区间内最小值*区间内元素的和)值最大。

解析:首先如果用暴力的话,我们可以枚举n个数,对每一个数我们先假定它为区间内的最小值,并从这个值开始想左右两侧延伸,如果碰到比这个数大的数则继续向一侧延伸,否则终止,两侧都终止时得到的区间即为以这个数为最小值所能得到的所求值最大的区间,复杂度应为n^2,显然会超时。实际上这个题需要用到单调栈。

关于单调栈和该题,这里直接引用另一篇博客的内容:

http://www.cnblogs.com/ziyi--caolu/archive/2013/06/23/3151556.html


最后附上代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <functional>
//#include <iomanip.h>
#include <limits.h>
//#include <strstrea.h>
//#include <fstream.h>
#define ll long long
#define ull unsigned long long
//#define int64 long long
#define INF  0x3f3f3f3f

using namespace std;

const int maxn = 1e5 + 5;
int n;

struct node {
    int num;
    int pre;
    int next;
    int k;
};

ll s[maxn], t[maxn];

stack<node> st;

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("data.out", "w", stdout);
    scanf("%d", &n);
    ll ans = -100, sum = -100;
    s[0] = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%I64d", &t[i]);
        if (i == 1)
            s[i] = t[i];
        else
            s[i] = s[i - 1] + t[i];
    }
    node tmp;
    tmp.num = t[1];
    tmp.next = tmp.pre = 1;
    tmp.k = 1;
    st.push(tmp);
    int x, y;
    for (int i = 2; i <= n; i++) {
        node tmp1;
        tmp1.num = t[i];
        tmp1.next = tmp1.pre = 1;
        tmp1.k = i;
        while (!st.empty() && tmp1.num <= st.top().num) {
            tmp = st.top();
            st.pop();
            if (!st.empty())
                st.top().next += tmp.next;
            tmp1.pre += tmp.pre;
            ans = tmp.num * (s[tmp.k + tmp.next - 1] - s[tmp.k - tmp.pre]);
            if (ans >= sum) {
                sum = ans;
                x = tmp.k - tmp.pre + 1;
                y = tmp.k + tmp.next - 1;
            }
        }
        st.push(tmp1);
    }
    while (!st.empty()) {
        tmp = st.top();
        st.pop();
        if (!st.empty())
            st.top().next += tmp.next;
        ans = tmp.num * (s[tmp.k + tmp.next - 1] - s[tmp.k - tmp.pre]);
        if (ans >= sum) {
            sum = ans;
            x = tmp.k - tmp.pre + 1;
            y = tmp.k + tmp.next - 1;
        }
    }
    printf("%I64d\n%d %d", sum, x, y);
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}

需要注意的是此题读入数据很大,用cin会超时,所以用scanf。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值