POJ3250-Bad Hair Day
题目描述
Description
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:
=
= =
= _ = Cows facing right -->
= = =
= _ = = =
= = = = = =
1 2 3 4 5 6
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.
Input
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.
Output
Line 1: A single integer that is the sum of c1 through cN.
Sample Input
6
10
3
7
4
12
2
Sample Output
5
思路介绍
简述一下这道题目的题意,一群高矮不同的牛排成一列,每头牛都只能看到他前面比他矮的牛的脑袋,如果他面前有比他还高的牛,那么那头高牛就会挡住这头牛的视线,让这头牛不能继续往前看,问队伍中每头牛能看到脑袋的数量加起来总共有多少。
这道题目的核心,就是单调栈的使用。要知道单调栈的适用于解决什么样的问题,我们首先需要知道单调栈的作用。单调栈分为单调递增栈和单调递减栈,通过使用单调栈我们可以访问到下一个比他大(小)的元素(或者说可以)。也就是说在队列或数组中,我们需要通过比较前后元素的大小关系来解决问题时我们通常使用单调栈。
这道题目用到的是单调递减栈,所以我们就拿单调递减栈为例。我们遍历整个数组,一次读取每个元素。如果当前栈为空,那么就将该元素直接入栈;如果当前栈不为空,那么就从栈顶将栈中值小于当前元素的成员弹出,再将该元素压入栈(如果栈中没有比该元素小的成员,就将该元素直接压入栈)。因为这个栈是单调递减的,即离栈底远近值越大,离栈顶越近值越小,所以当找到栈中第一个比该元素大的成员时,栈中所有比该元素小的成员都会被全部弹出,换句话说,该元素就是栈中最小的成员。而这个过程模拟的就是题目中的实验过程。
让我们来思考一下,什么时候栈中的成员会被弹出?
只有当读取到的元素第一次比该成员大的时候,他才会被弹出!!! 如果读取到的元素比该成员小,那么这个元素会直接入栈,而如果后面再读到更大的元素,这个成员早已弹出。所以只有当第一次读到一个比该成员大的数的时候,他才会被弹出,而在这个成员未被弹出的时候,数组中后面的成员都比该成员小。我们可以将元素在数组中的位置压入栈中,这样当该成员被弹出的时候,我们可以将当前元素在数组中的位置与该成员在数组中的位置做差再减一,这样就能求出在第一次遇到比该成员大的数之前,中间有几个元素,即在遇到比该牛更高的牛之前,这头牛能看到几个脑袋,满足题意。另外,为了让最后一个元素也能够弹出,我们可以在数组后面加上一个无限大的数,这样就能保证最后程序运行完后,栈为空。
AC代码
#include<iostream>
#include<stack>
using namespace std;
int main(void)
{
long long a[80005] = { 0 };
int n;
while (cin >> n)
{
stack<int>st;
long long ans = 0;
for (int i = 0; i < n; i++)
cin >> a[i];
a[n] = 1000000005;
for (int i = 0; i <= n; i++)
{
while (!st.empty() && a[st.top()] <= a[i])
{
int temp = st.top();
st.pop();
ans += (i - temp - 1);
}
st.push(i);
}
cout << ans << endl;
}
return 0;
}
小结
单调栈的作用:
1、给定一组数,针对每个元素,寻找它和它右边第一个比它大的元素之间有多少个数。
2、给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大。
3、给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大。