【单调栈】洛谷1823 Patrik音乐会的等待

一道单调栈的水题,看起来很简单,但是如给我看这道题的zwz大佬所说,细节非常麻烦,并且有一定思维难度

传送门

题目描述

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

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

输入输出格式

输入格式:

输入的第一行包含一个整数N (1 ≤ N ≤ 500 000), 表示队伍中共有N个人。

接下来的N行中,每行包含一个整数,表示人的高度,以毫微米(等于10的-9次方米)为单位,每个人的调度都小于2^31毫微米。这些高度分别表示队伍中人的身高。

输出格式:

输出仅有一行,包含一个数S,表示队伍中共有S对人可以互相看见。

输入输出样例

输入样例: 
7
2 4 1 2 2 5 1
输出样例:

10

* 这题的大体思路是,维护一个单调栈h[],遇到需要弹出的情况说明需弹出元素和当前元素间没有比他们高的,ans++

* 弹完一遍如果栈里还剩下东西,那么剩下的栈顶元素与当前元素之间也能互相看到,ans++

* 最难的是处理相等的高度,其实相等的高度且可以相互看到的人可以看成同一个人,比如2,2,1,2,2,这四个高度为2的可以在处理掉1之后看成一个整体,然而2,2,5,2,2,的四个2就不行

* 所以我们新开一个g[i]表示在单调栈内和h[i]相同高度的元素数量,每次遇到与当前元素相同的高度,ans+=g[i]

* 最后代码写成酱紫,因为细节又wa又tle又re,真是心累

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N = 5e5+10;
int n;
int h[N], g[N], t;
long long ans;


int main()
{
    scanf("%d", &n);
    ans = 0;
    t = 0;
    for (int i = 1; i <= n; i++){
        int l;
        scanf("%d", &l);
        while (t && l > h[t])
            ans++, t--;
        if (t && l == h[t]){
            if (t-g[t]) ans++;
            ans += g[t];
            h[++t] = l;
            g[t] = g[t-1]+1;
        }
        else{
            if (t) ans++;
            h[++t] = l;
            g[t] = 1;
        }
    }
    printf("%lld", ans);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/xyyxyyx/article/details/80962056