P1823 [COI2007] Patrik 音乐会的等待

题目描述

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

说明/提示

数据制作: @w

2018.6.29添加3组数据

【思路】

单调栈

很有意思的一道题目

【题目大意】

一个队列

两个人中间只要没有比他俩其中一个高的就可以相互看见

求能够相互看见的对数

【理智分析】

这对点能够互相看见是基于两者之间没有比他们任何一者高的基础上的

一个人能够看见最远的一个人就是两边第一个比他高的

这很显然对吧?

因为第一个比他高的之后的人就被他挡住了

(贴合实际)

然后如果这个人和一边第一个比他高的人

中间的人不一定能够全部被这个人看见

【举例】

因为:

1 1 4 5 1 4 1 9 1 9

位置8上的那个9右边能看到最远的就是位置1上的1

但是位置1到位置8之间所有的数

他不是都能够彼此看见的

比如位置5上的那个1

就不能彼此看见

因为中间有一个位置6上的4是比1高的

所以彼此看不见

看一下位置8上的9右边能够看到的数

5 4 1

很显然这是一个大向右递增的区间

因为你看到了右边第一个之后

看到的右边第二个不能够比右边第一个要低

不然就是不能够被看见的

【呼之欲出】

是不是很显然了?

这不就是单调栈吗!?

【最终思路】

上面的过程完全就是在单调栈的过程对吧

如果栈里面的栈顶元素比手上这个元素要小

那栈顶元素左边能够看到的最后一个元素就是手上这个了

再也看不到别的了

这就是1对可以互相看见

弹出就好了

然后手上这个继续和栈顶去比较

【注意】

两个一样高的人是可以相互看见的

1 1 1 1 1

这串数字里面

第一个1是可以和最后一个1相互看见的

千万不要忽略哦

然后就是怎么处理上面这种情况了

一开始我想的是暴力从栈里面取出来

计数有多少个

计完数之后再放回栈

这样就超时了两个点

这两个点我下载了一个点的测试数据看来一下

500000个一样的10

不超时才怪……

所以 可以在栈中存一个结构体

记录这个人的高度和人数

也就是和她一样高的并且在栈中位置是紧挨着的

遇到和她一样的情况只需要将其弹出

然后在弹入一个v(计数多少个人) + 1的就好了

【完整代码】

【80分暴力出栈代码】

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
const int Max = 500005;
int a[Max];
stack<int>s;
int main()
{
int n;
cin >> n;
for(register int i = 1;i <= n;++ i)
cin >> a[i];
int js = 0;
for(register int i = 1;i <= n;++ i)
{
int jj = 0;
while(!s.empty() && a[i] >= s.top())
{
if(a[i] == s.top())
{
while(!s.empty() && s.top() == a[i])
s.pop(),jj ++,js ++;
}
else
{
s.pop();
js ++;
}
}
if(!s.empty())
js ++;
while(jj --)
s.push(a[i]);
s.push(a[i]);
}
cout << js << endl;
return 0;
}

【AC代码】

#include<iostream>
#include<cstdio>
#include<stack>
#define int long long
using namespace std;
const int Max = 500005;
struct node
{
int h;
int v;
}a[Max];
stack<node>s;
signed main()
{
// freopen("music.in","r",stdin);
int n;
cin >> n;
for(register int i = 1;i <= n;++ i)
cin >> a[i].h,a[i].v = 1;
int ans = 0;
for(register int i = 1;i <= n;++ i)
{
while(!s.empty() && a[i].h > s.top().h)
{
ans += s.top().v;
s.pop();
}
if(!s.empty() && a[i].h == s.top().h)
{
node qwq = s.top();
ans += s.top().v;
s.pop();
if(!s.empty())
ans ++;
s.push((node){qwq.h,qwq.v + 1});
}
else
{
if(!s.empty())
ans ++;
s.push(a[i]);
}
}
cout << ans << endl;
return 0;
}
04-30 10:33