• 单调栈学习笔记


    第一题

    题目描述

    约翰有N头奶牛,编号为1到N。

    现在这N头奶牛按编号从小到大的顺序站成了一排,其中奶牛 i 的身高为Hi。

    现在,每头奶牛都向它的右侧望向那些编号较大的奶牛,对于奶牛 i 如果存在一头奶牛 j 满足 (i<j) 并且 (H_i<H_j),那么我们称奶牛 i 需要仰视奶牛 j。

    请你求出每头奶牛的最近仰视对象。

    输入格式
    第一行包含整数N。

    接下来N行,每行包含一个整数(H_i),其中第 i 行的数为编号为 i 的奶牛的高度。

    输出格式
    共 N 行,每行输出一个整数,其中第 i 行的输出整数表示编号为 i 的奶牛的最近仰视对象的编号,如果不存在仰视对象,则输出0

    数据范围
    (1 le N le 10^5)
    (1 le H_i le 10^6)
    输入样例:

    6 
    3 
    2 
    6 
    1 
    1 
    2 
    

    输出样例:

    3 
    3 
    0 
    6 
    6 
    0 
    

    解题思路

    题意分析

    这道题目大致意思是:每一头奶牛往右看,找到离自己最近,而且比自己身高高的牛,
    如果没有比自己高的牛,那么输出0即可.也就是无解判断

    算法分析

    首先我们知道程序=数据结构+算法,这道题目算法,我们除了暴力+模拟,实在想不到任何解题思路.可能是我太蠢了

    所以我们考虑如何通过数据结构来优化这道题目.

    数据结构

    对于一道题目而言,我们需要对于条件,性质两处地方动手,来思考算法或者数据结构的突破口,显然这道题目数据结构的确定,同样离不开这条不定的定律.

    对于这道题目而言,我们主要是分析条件,因为我们发现这道题目所有的奶牛,都在找离着自己最近的奶牛,那么我们不得不思考,是不是要用到后进先出的栈

    既然现在我们已经确定,数据结构大致为栈,那么现在我们就需要分析性质了.

    分析性质

    这道题目,最有用的性质,就是离自己最近,而且比自己身高高.

    1. 离自己最近:这个性质其实就是我们所谓的栈的必备性质.
    2. 身高高:看到这种类型的词汇,一定要第一时间反应,这道题目是不是拥有单调性.

    经过上面的讨论,我们大致可以确定,这道题目的确拥有单调性,那么想让我们的数据结构栈,就进化成为了单调栈.

    算法整合

    我们可以一步步读入奶牛,对于每一头奶牛而言,判断这一头奶牛可以成为哪些奶牛的仰视对象.
    于是,我们可以将当前奶牛,不断地和栈顶奶牛比较,如果说它身高大于栈顶奶牛,那么栈顶奶牛的仰视对象一定是当前奶牛,然后将栈顶奶牛出栈,进行下一次比较,直到栈为空或者栈顶奶牛身高高于它.最后再将我们当前奶牛的身高入栈.

    之所以仰视对象是当前奶牛,因为它是离栈顶奶牛最近的奶牛,而且满足身高大于它.

    可以略微证明一下,因为如果说栈顶奶牛的仰视对象不是当前这头奶牛,那么在这头奶牛之前,栈顶奶牛肯定已经出栈了,因为必然在此之前,会有奶牛成为栈顶奶牛的仰视对象,然而现在它还在栈中,那么栈顶奶牛的仰视对象,必然是当前这头奶牛.

    代码
    #include <bits/stdc++.h>
    using namespace std;
    const int N=101000;
    int n,m,i,j,k,a[N],s[N];
    stack<pair<int,int> > q;
    int main()
    {
        ios::sync_with_stdio(false);//优化不可少
        cin>>n;
        for(int i=1; i<=n; i++)
            cin>>a[i];
        for(int i=1;i<=n;i++)
        {
            while (q.size() && a[i]>q.top().first)//栈内有奶牛,且身高大于栈顶的奶牛
            {
                s[q.top().second]=i;//仰视对象
                q.pop();
            }
            q.push(make_pair(a[i],i));//加入栈中
        }
        for(int i=1;i<=n;i++)
            cout<<s[i]<<endl;//输出即可
        return 0;
    }
    

    第二题

    题目描述

    某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 (H_i),并能向两边(当然两端的只能向一边)同时发射能量值为 (V_i) 的能量,并且发出的能量只被两边最近的且比它高的发射站接收

    显然,每个发射站发来的能量有可能被 0 或 1 或 2 个其他发射站所接受,出于安全考虑,每个发射站接收到的能量总和是我们很关心的问题。

    由于数据很多,现在只需要你帮忙计算出接收最多能量的发射站接收的能量是多少。

    输入格式
    第一行包含整数N。

    接下来N行,每行包含两个整数(H_i)(V_i),其中第 i 行的数据为第 i 个发射站的高度和能量值。

    输出格式
    输出仅一行,表示接收最多能量的发射站接收到的能量值。

    数据保证答案不超过(2^{31}-1)

    数据范围
    (1 le N le 10^6),
    (1 le H_i le 2*10^9),
    (1 le V_i le 10000)

    输入样例:

    3
    4 2 
    3 5 
    6 10
    

    输出样例:

    7
    

    解题思路

    题意分析

    N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 (H_i),并能向两边同时发射能量值为 (V_i) 的能量,并且发出的能量只被两边最近的且比它高的发射站接收。然后要我们求出这个最大的接受能量值是多少.

    思路分析

    首先我们知道程序=数据结构+算法,这道题目算法,我们除了暴力+模拟,实在想不到任何解题思路.可能是我太蠢了

    所以我们考虑如何通过数据结构来优化这道题目.

    数据结构

    既然现在我们已经想到了数据结构来优化算法,那么现在当前最大的问题.无非就是如何利用这个我们学过数据结构来优化这道题目.

    我们发现这道题目,所有的数字都满足一个非常重要的性质,那就是发出的能量只被两边最近的且比它高的发射站,我们从中间,不但会发现这道题目的条件,还会发现这道题目出题人,偷偷告诉我们的性质.那就是两边最近且比他高.

    性质分析

    两边最近: 显然,是一个条件&性质,而且这里面最为重要的性质核心,就是最近这个两个字.

    看到这里,我们就得让神经系统中的神经元,条件反射地想到,是不是需要后进后出的数据结构栈

    比他高: 这就是这道题目的第二大精髓思想,单调性,我们通过这道题目的这句话,可以敏锐地察觉到,这道题目需要使用具有单调性质的单调栈.

    算法步骤

    这道题目既然是需要使用具有非常秀的单调栈,那么我们到底如何使用呢?

    那么此时我们就需要根据条件,来确定单调栈,插入栈顶的条件.

    因为对于一个发射站而言,它可以接收到的能量,就是一组单调递减的高度序列的能量.这里我们需要画图解决问题.

    综上所述,我们可以开一个单调递减的栈,统计所有高度单调递减的发射站.

    1. 如果当前这个数字破坏了单调递减,那么它会挡掉比它矮的所有发射站.
      然后将所有比它能量小的发射站,统统吸取.然后将这些发射站出栈,自己入栈.
    2. 如果当前发射站,满足单调递减的话,那么栈顶所属的发射站,吸取它的能量.同样自己也需要入栈
    代码实现
    #include <bits/stdc++.h>
    using namespace std;
    const int N=1001000;
    pair<int,int> p[N];
    int top,x,n,m,i,j,s[N],a[N],b[N],ans,top2;
    int main()
    {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1; i<=n; i++)
            cin>>a[i]>>b[i];//读入
        p[++top].first=a[1];//first存储高度
        p[top].second=1;//存储这个发射塔的位置
        for(int i=2; i<=n; i++)
        {
            while (a[i]>p[top].first && top)
                s[i]+=b[p[top--].second];//将这个发射塔的能量吸取
            s[p[top].second]+=b[i];//栈顶吸收我这个发射塔的能量
            p[++top]=make_pair(a[i],i);//插入栈中
        }
        for(int i=1; i<=n; i++)
            ans=max(ans,s[i]);
        cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    AOP
    资料
    有用快捷键
    Java中getResourceAsStream的用法
    【转载】URL编码与两次encodeURI
    maven 如何使用
    MyEclipse运行Java出错:could not find the main class:test.program will exit(导入项目)
    java集合的操作(set,Iterator)
    java类集框架(ArrayList,LinkedList,Vector区别)
    java线程控制安全
  • 原文地址:https://www.cnblogs.com/gzh-red/p/11019265.html
Copyright © 2020-2023  润新知