一道单调栈的水题,看起来很简单,但是如给我看这道题的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;
}