题目描述
N个人正在排队进入一个音乐会。人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人。队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的。
写一个程序计算出有多少对人可以互相看见。
输入输出格式
输入格式:
输入的第一行包含一个整数N (1 ≤ N ≤ 500 000), 表示队伍中共有N个人。
接下来的N行中,每行包含一个整数,表示人的高度,以毫微米(等于10的-9次方米)为单位,每个人的调度都小于2^31毫微米。这些高度分别表示队伍中人的身高。
输出格式:
输出仅有一行,包含一个数S,表示队伍中共有S对人可以互相看见。
输入输出样例
输入样例#1: 复制
7
2
4
1
2
2
5
1
输出样例#1: 复制
10
解题思路
对于每一对人,能互相看见的前提是,他们中间没有比他们两个中任何一个高的人。我们让每个人按照顺序入栈,在入栈前,先查看栈顶的人是不是比自己高,如果栈顶的人比自己矮,那么自己可以看到栈顶的人,和它的前一个人,但是对于栈顶的人来说,自己比他高就把自己后面的人都挡住了,他已经不能再看到后面的人了,所以让他出栈。直到栈顶是第一个比自己高的人,也就是自己往前看所能看到的最后一个人。
但是呢,人的高度可以相同,且一样的高度的人是不会互相挡住的。难道要把一样的全出栈直到找到第一个大的再全入栈么?时间就不行了,所以可以用结构体存这个高度,和这个高度在栈中的连续数。这样只要出一次,进一次就可以了。
代码如下
#include <iostream>
#include <stack>
#include <cstdio>
using namespace std;
typedef long long ll;
struct T{
int x;
ll cnt;
};
stack<T> sta;
int main()
{
int n;
cin >> n;
ll ans = 0;
for(int i = 1; i <= n; i ++){
int high;
scanf("%d", &high);
T temp;
temp.x = high;
temp.cnt = 1;
while(!sta.empty()){
T top = sta.top();
if(top.x > high){
ans ++; //可以看到比自己高的第一个人
break;
}
else {
ans += top.cnt;
sta.pop();
if(top.x == high) //高度相同
temp.cnt += top.cnt; //则把这些数量加到要入栈的节点中去
}
}
sta.push(temp);
}
cout << ans << endl;
return 0;
}