POJ 2796 Feel Good (单调栈的应用)

原题地址:http://poj.org/problem?id=2796
题意:给出一个序列,求出一个子序列,使得这个序列中的最小值乘以这个序列的和的值最大。

思路:单调栈的简单应用,带了详细的注释

#include<stdio.h>
#include<iostream>
#include<stack>
using namespace std;
typedef long long LL;
/*
POJ 2796
求区间元素和乘以区间最小值最大
单调递增栈
*/
int main() {
    int i, n, pos1, pos2;
     //pos1和pos2记录区间的开始和结束位置
    //tmp为临时变量,记录区间内的和;top指向栈顶元素;ans为结果;sum为前缀和
    LL tmp, top, ans, a[100010], sum[100010];
    stack<int> st; //单调栈,记录元素位置
    while(~scanf("%d", &n)) {
        while(!st.empty()) st.pop(); //清空栈
        sum[0] = 0;
        for(i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            sum[i] = sum[i - 1] + a[i]; //计算前缀和
        }
        a[n + 1] = -1; //将最后一个设为最小值,以最后让栈内元素全部出栈
        //单调递增栈
        ans = 0;
        for(i = 1; i <= n + 1; i++) {
            if(st.empty() || a[i] >= a[st.top()]) {
                //如果栈为空或入栈元素大于等于栈顶元素,则入栈
                st.push(i);
            } else {
                while(!st.empty() && a[i] < a[st.top()]) {
                    //如果栈非空并且入栈元素小于栈顶元素,则将栈顶元素出栈
                    top = st.top();
                    st.pop();
                    tmp = sum[i - 1] - sum[top - 1]; //计算区间内元素和
                    //其实就是该数的右端点和左端点
                    tmp *= a[top]; //计算结果
                    if(tmp >= ans) {//等于号是为了处理0这种情况
                        //更新最大值并记录位置
                        ans = tmp;
                        pos1 = top;
                        pos2 = i;
                    }
                }
                st.push(top); //将最后一次出栈的栈顶元素入栈
                a[top] = a[i]; //将其向左向右延伸并更新对应的值,更新左端点
            }
        }
        printf("%lld\n", ans);
        printf("%d %d\n", pos1, pos2 - 1);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81514364
今日推荐