zoukankan      html  css  js  c++  java
  • 单调栈总结

    单调栈总结


    前言

    刷了几道题没发现啥特别的用处,基本都是个板子;

    单调栈可以O(n)的求一个序列中每个数左(右)边第一个大于(小于)他的位置;


    例题

    美丽的序列

    为了研究这个序列的美丽程度,GD定义了一个序列的“美丽度”和“美丽系数”:对于这个序列的任意一个区间[l,r],这个区间的“美丽度”就是这个区间的长度与这个区间的最小值的乘积,而整个序列的“美丽系数”就是它的所有区间的“美丽度”的最大值。现在GD想要你帮忙计算这个序列的“美丽系数”。

     

    其实就是个板子,考虑每个数字能够控制的区间就是右边第一个小于他的数字到左边第一个小于他的数字之间,单调栈秒

    海报PLA

    每个建筑物有高和宽,用矩形海报覆盖所有建筑物,求最少需要几张海报;

    考虑到一张海报要贴必定是扩展到左右最远处最优,而不同的高度差意味着需要不同的海报;

    换句话说,相同高度的两个建筑可以共用一张海报完成,所以初始ans=n,在单调栈过程中遇到相同高度ans-1即可

    音乐会的等待

    N个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。

    写一个程序计算出有多少对人可以互相看见。

    搞一下单调栈,栈内每有一个小于自己的元素就++ans,高度相同的不应该弹栈,就用二元组记录当前高度有多少人

    贴代码

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read()
    {
        int x=0,f=1;
        char ch;
        for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
        if(ch=='-') f=0,ch=getchar();
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    typedef pair<int,int> p;
    int n,ans,top;
    p st[1000010];
    signed main()
    {
        n=read();
        for(int x,i=1;i<=n;++i)
        {
            x=read();
            p now(x,1);
            for(;top&&x>=st[top].first;--top)
            {
                ans+=st[top].second;
                if(x==st[top].first) now.second+=st[top].second;
            }
            ans+=(top!=0);
            st[++top]=now;
        }
        printf("%lld
    ",ans);
    return 0;
    }

    长方形

    给定n*m的01矩阵,求全部由1组成的矩阵的个数;

    对于每个点(i,j)预处理出一个h[ i ][ j ]表示从(i,j)向上最多能延伸远

    找出l[ i ][ j ]和r[ i ][ j ] 表示左边第一个h[ i ][ j ]第一个不大于当前h[ i ][ j ]的位置和右边第一个小于当前h[ i ][ j ]的位置

    这样可以做到不重不漏

    ans+=(j - l[ i ][ j ])*(r[ i ][ j ] - j)* h[ i ][ j ];

    式子解释:左边在 j 到 l[ i ][ j ]之间任选位置,右边在r到r[ i ][ j ]之间任选位置,高度在1到h[ i ][ j ]之间任选位置,组合数学QAQ

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read()
    {
        int x=0,f=1;
        char ch;
        for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
        if(ch=='-') ch=getchar(),f=0;
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return f?x:-x;
    }
    int n,m,res;
    int mp[1010][1010];
    int h[1010][1010];
    int l[1010],r[1010];
    int st[1010],top;
    char ch;
    inline void work(int x)
    {
        top=0;
        for(int i=1;i<=m;++i)
        {
            while(top&&h[x][st[top]]>=h[x][i])
            {
                r[st[top--]]=i;
            }
            st[++top]=i;
        }
        while(top)
        {
            r[st[top--]]=m+1;
        }
        for(int i=m;i>=1;--i)
        {
            while(top&&h[x][st[top]]>h[x][i])
            {
                l[st[top--]]=i;
            }
            st[++top]=i;
        }
        while(top)
        {
            l[st[top--]]=0;
        }
    }
    signed main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=m;++j)
            {
                for(ch=getchar();(ch!='.'&&ch!='*');ch=getchar());
                if(ch=='.') mp[i][j]=1,h[i][j]=h[i-1][j]+1;
            }
        }
        for(int i=1;i<=n;++i)
        {
            work(i);
            for(int j=1;j<=m;++j)
            {
                res+=(j-l[j])*(r[j]-j)*h[i][j];
            }
        }
        printf("%lld
    ",res);
    return 0;
    }

    玉蟾宫

    给定01矩阵,求最大的全部由1构成的矩阵;

    与上一题思路类似,这一题求出左右第一个小于的位置然后直接算最大

     

  • 相关阅读:
    [Linux 004]——用户和用户组以及 Linux 权限管理(二)
    [Linux 003]——用户和用户组以及 Linux 权限管理(一)
    [Linux 002]——Linux的常用命令
    [Linux 001]——计算机和操作系统的基础知识
    给 Android 开发者的 RxJava 详解
    Mac OSX系统搭建React natvie for android 开发环境
    Java中的堆和栈的区别
    Nginx配置详解
    在博客园安家了!
    J2SE核心实战开发—— 集合类框架
  • 原文地址:https://www.cnblogs.com/knife-rose/p/11492184.html
Copyright © 2011-2022 走看看