zoukankan      html  css  js  c++  java
  • 单调栈 && 洛谷 P2866 [USACO06NOV]糟糕的一天Bad Hair Day(单调栈)

    传送门


    这是一道典型的单调栈。


    题意理解

    先来理解一下题意(原文翻译得有点问题)

    其实就是求对于序列中的每一个数i,求出i到它右边第一个大于i的数之间的数字个数c[i]。最后求出和。

    首先可以暴力求解,时间复杂度o(n^2)显然TLE。

    然后就是用单调栈来做。

    单调栈

    单调栈就是维护一个栈,使得栈中的元素是单调的(递增/递减)。

    假设是递减——对于每一个新来的元素,把栈顶大于这个元素的每一个数字全部弹出,最后把这个元素加进去。

    (如果栈为空,直接加入)

    单调栈有什么用呢?

    • 单调递增栈能以o(n)时间复杂度求出左右两边第一个比它比它小的元素。
    1. 进栈元素能入栈的时候,此时栈顶元素一定是第一个左边第一个比进栈元素小的元素。
    2. 栈内元素出栈的时候,此时进栈元素一定是第一个右边第一个比栈顶元素小的元素。
    • 单调递减栈能以o(n)时间复杂度分别求左右两边第一个比它大的元素。
    1. 进栈元素能入栈的时候,此时栈顶元素一定是第一个左边第一个比进栈元素大的元素。
    2. 栈内元素出栈的时候,此时进栈元素一定是第一个右边第一个比栈顶元素大的元素。

    解题思路

     因为这道题求的是最大的元素,所以用单调递减栈。

    第一种方法就是对于每一个元素,求出其右边第一个大于它的元素,最后作差求和。

    第二种更为简单却难以思考的方法是对于每一个即将进栈的数,ans就加上此时(该元素还未进栈)栈内的元素个数。

    为什么呢?

    此时对于栈内的所有元素,一定是呈单调递减的,所以这个即将进栈的元素就能被栈内的元素看到,所以答案加上栈内的元素个数。

    注意事项

    • 用long long,否则会爆。
    • 注意读题,出栈的条件是<=而不是<。
    • while循环&&的s.size()条件必须放在左边。

    AC代码

     1 #include<iostream>
     2 #include<stack>
     3 #include<cstdio> 
     4 using namespace std;
     5 long long ans;
     6 stack<int>s;
     7 int n,now;
     8 int main(){
     9     cin>>n; 
    10     for(int i=1;i<=n;++i)
    11     {
    12         scanf("%d",&now);
    13         while(s.size()&&s.top()<=now) s.pop();
    14         ans+=s.size();
    15         s.push(now);
    16     }
    17     cout<<ans;
    18     return 0;
    19 }
  • 相关阅读:
    JavaScript初学者应注意的七个细节
    KindEditor 编辑器使用方法
    有关 JavaScript 的 10 件让人费解的事情
    能说明你的Javascript技术很烂的五个原因
    分享10个便利的HTML5/CSS3框架
    现在就使用HTML5的十大原因
    你应该知道的Node.js扩展模块——Hashish
    C++ Tip: How To Get Array Length | Dev102.com
    MPI for Python — MPI for Python v1.3 documentation
    http://construct.readthedocs.org/en/latest/basics.html
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/11729756.html
Copyright © 2011-2022 走看看