跳到主要内容

P2866 糟糕的一天

题面翻译

农夫约翰有N(N80000)N (N \leq 80000)头奶牛正在过乱头发节。每一头牛都站在同一排面朝东方,而且每一头牛的身高为hih_i。第NN头牛在最前面,而第11头牛在最后面。 对于第ii头牛前面的第jj头牛,如果hi>hi+1h_i>h_{i+1}并且hi>hi+2h_i>h_{i+2} \cdots hi>hjh_i>h_j,那么认为第ii头牛可以看到第i+1i+1到第jj头牛。

定义CiC_i为第ii头牛所能看到的别的牛的头发的数量。请帮助农夫约翰求出i=1nCi\sum_{i=1}^n C_i

题目描述

Some of Farmer John's N cows (1 ≤ N ≤ 80,000) are having a bad hair day! Since each cow is self-conscious about her messy hairstyle, FJ wants to count the number of other cows that can see the top of other cows' heads.

Each cow i has a specified height hi (1 ≤ hi ≤ 1,000,000,000) and is standing in a line of cows all facing east (to the right in our diagrams). Therefore, cow i can see the tops of the heads of cows in front of her (namely cows i+1, i+2, and so on), for as long as these cows are strictly shorter than cow i.

Consider this example:

        -
- -
- - -
- - -
- - - - -
- - - - - -
1 2 3 4 5 6

Cows facing right -->

Cow#1 can see the hairstyle of cows #2, 3, 4

Cow#2 can see no cow's hairstyle

Cow#3 can see the hairstyle of cow #4

Cow#4 can see no cow's hairstyle

Cow#5 can see the hairstyle of cow 6

Cow#6 can see no cows at all!

Let ci denote the number of cows whose hairstyle is visible from cow i; please compute the sum of c1 through cN.For this example, the desired is answer 3 + 0 + 1 + 0 + 1 + 0 = 5.

输入格式

Line 1: The number of cows, N.

Lines 2..N+1: Line i+1 contains a single integer that is the height of cow i.

输出格式

Line 1: A single integer that is the sum of c1 through cN.

样例 #1

样例输入 #1

6
10
3
7
4
12
2

样例输出 #1

5

题目分析

仔细阅读题目,题目要求没头牛能看到的牛的数量的总和。分析下样例。

10 3 7 4 12 2

一次计算每头牛能看到的牛。

10: 3、 7、 4,能看到3头牛,之所以没有2,是因为v中间有个12,挡住了2。

3:一个都看不到。

7:4,能看到1头牛。

4:一个都看不到。

12:2,能看到1头牛。

2:一个都看不到。

总数为3+1+1=53+1+1=5

看起来只要从后往前扫,求出比h[i]小的数即可。但是这样做存在一个问题,该问题在样例中也有体现,即会出现“遮挡”的情况,比如样例中的2会被12给遮挡。而如果加入“遮挡”的计算起来会过于复杂。

此时可以更换一个思路,从原来的统计比h[i]小、且未被遮挡的元素个数改为统计能未遮挡的看到h[i]的元素个数。

更换思路之后,问题就变成了统计1i11\sim i-1 范围内的未遮挡的单调减的元素个数。这部分我们可以采用单调栈的思想进行实现。

单调栈,就是栈中元素具有单调性,例如单调增或单调减。

每次将栈顶元素不断和当前元素进行比较,若栈顶元素小于等于当前元素则进行出栈,不断重复,直到栈中元素能与当前元素构成一个具有单调减性质的序列。

while(!s.empty()&&s.top()<=x){
s.pop();
}

最终答案就是累加每个元素能被看到的元素数量的总和。

代码实现

#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
const int N=8e4+5;
typedef long long ll;
stack<int> s;//定义栈
int main(){
int n,x;
ll sum=0;//最终的总和
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
while(!s.empty()&&s.top()<=x){//不断将<=x的元素出栈
s.pop();
}
sum+=s.size();//累加能看到x的元素个数
s.push(x);//栈中元素呈单调减
}
cout<<sum;
return 0;
}