zoukankan      html  css  js  c++  java
  • POJ 2796:Feel Good 单调栈

    题目,给定一个数列,n <= 1e5 。要求找出一个区间,使得其内区间最小值 * 区间总和的值最大,要求输出区间。

    首先先维护一个单调递增的栈,同时记录一个lef值表示:lef[i]表示当前栈内这个元素能匹配的最左值,什么意思呢?就是在最左边那里,它是最小的。a[lef[i] - 1] < a[lef[i]] 的。这样的话,每次弹出一个元素,我就能知道它在那个区间内最小的,左区间是lef[i],右区间栈顶元素的位置。这样是最优的,因为你匹配多一些大的数字更好。

    用simple来说

    3 1 6 4 5 2

    开始的时候,是3入栈,记录lef[1] = 1。我简陋写为 3 (1,1)

    然后是1了,比3小,所以3出栈,3出栈后注意了,要计算,最左区间,自然是1,最右区间,就是当前栈顶元素的位置,也是1。tans = 9;  然后要跟新1的最左值,是1。

    6进来,直接进。1 (1,2) , 6 (3, 3)

    然后4进来,弹出6,计算6.栈内是 1 (1,2)  4(3, 4)

    5进来。栈内是 1 (1,2)  4(3, 4)5(5,5)

    2进来。把5弹出,计算5.

    把4弹出,注意了。区间是4的最左值,最右值是栈顶元素的位置,当前栈顶元素是5,位置是5.所以表明4在{6,4,5}最小。计算。

    主要是弹出一个元素,就要对那个元素进行 计算。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 100000 + 20;
    int a[maxn];
    int stack[maxn]; //只保存位置即可,大小关系可以调用a[stack[top]] 判断
    int lef[maxn]; //传入栈的位置,就可以得到对应元素在最左区间内最小
    LL sum[maxn];
    void work ()
    {
        int n;
        scanf ("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf ("%d", &a[i]);
            sum[i] = sum[i - 1] + a[i];
        }
        a[n + 1] = -1; //防止全部都是递增
        LL ans = -1, L, R;
        int top = 0;
        for (int i = 1; i <= n + 1; ++i) {
            int TT = stack[top]; // 栈内元素到栈顶元素,这个区间最小值
            int toleft = i; //保存插入后上一个元素的最左值
            while (top >= 1 && a[i] < a[stack[top]]) { //等于的话,不如让它扩大
                LL t = (sum[TT] - sum[lef[stack[top]] - 1]) * a[stack[top]];
                if (t > ans) {
                    ans = t; L = lef[stack[top]]; R = TT;
                }
                toleft = lef[stack[top]];
                --top;
    //            printf ("%d
    ", top);
    //            printf ("%lld****
    ", ans);
            }
            ++top;
            stack[top] = i;
            lef[stack[top]] = toleft;
            //printf ("%d %d %d
    ", top, lef[stack[top]], stack[top]);
        }
        printf ("%lld
    ", ans);
        printf ("%lld %lld
    ", L, R);;
        return ;
    }
    int main ()
    {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        work ();
        return 0;
    }
    View Code
  • 相关阅读:
    毛笔算法 毛笔签名效果
    手写输入控件
    全栈工程师成长路线
    配置msdtc
    流行的广告轮播(图片轮播)JS代码!!
    水晶报表放上去网站会爆:bobj错误的
    查询所有存储过程
    VB.NET and C# Comparison
    SQL查询案例:多行转换为一行
    SQL Server行列转换[转]
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5821033.html
Copyright © 2011-2022 走看看