

在例题中,题目要求我们找到 每个数左边第一个比它小的数
我们可以先写出暴力做法,然后进一步优化
- for(int i = 0; i < n; i ++ )
- for(int j = i - 1; j >= 0; j -- )
- if(a[i] > a[j])
- {
- cout << a[j] << endl;
- break;
- }
我们可以用一个 栈 来维护相关的数据
我们可以发现,在栈中,有一些元素是不会作为答案输出的
假设
且满足
,那么 x 就不会作为答案输出,因此,在栈中可以维护一个单调上升的序列(每一次判断都可以删除所有逆序的点)
- #include <iostream>
- using namespace std;
-
- const int N = 100010;
-
- int n;
- int stk[N], tt;
-
- int main()
- {
- cin >> n;
-
- for(int i = 0; i < n; i ++ )
- {
- int x;
- cin >> x;
- while(tt && stk[tt] >= x) tt -- ;
- if(tt) cout << stk[tt] << ' ';
- else cout << -1 << ' ';
-
- stk[++ tt] = x;
- }
- return 0;
- }
输入样例:
7 2 1 4 5 1 3 3 4 1000 1000 1000 1000 0输出样例:
8 4000
假设所有的矩形的高度是从左向右单调递增的,那么答案是多少?
显而易见的,我们可以尝试以每个矩形的高度作为最终矩形的高度,并把宽度延伸到右边界,得到一个矩形,在所有的矩形面积中取最大值就是答案,如下图所示:

如果下一个矩形的高度比上一个小,那么该矩形想利用之前的矩形一起构成一个较大的面积的时候,这块面积的高度不可能超过该矩形自己的高度。换句话说,在考虑上述的几种情况后,下图中红色框框中的部分就丝毫没有用处了。

既然没有用处,我们可以把这些比该矩形高的矩形都删掉,用一个宽度累加、高度为该矩形自己的高度的新矩形(上图中的阴影部分)代替。这样不会对后续的计算产生影响。
于是我们维护的轮廓就变成了一个高度单调递增的矩形序列,问题变得可解。
详细的说,我们建立一个栈,用来保持若干个矩形,这些矩形的高度是单调递增的。
我们从左到右一次扫描每个矩形。
如果当前矩形比栈顶矩形高,直接进栈。
否则不断弹出栈顶,直到栈顶为空或者是栈顶的矩形高度比当前矩形小。在出栈的过程中,
我们累计计算被弹出的矩形的宽度之和,并且每弹出一个矩形,就用它的高度乘上累计的
宽度去更新答案。整个出栈过程结束后,我们把一个高度为当前矩形、宽度为累计值的新矩
形入栈。
简单来说,就是找到每一个高度,左边第一个比它矮的位置
,对应的面积就是
- #include <iostream>
- #include <algorithm>
- using namespace std;
-
- const int N = 100010;
-
- typedef long long LL;
-
- int n;
- int h[N], l[N], r[N], q[N];
-
- int main()
- {
- while(cin >> n, n)
- {
- for(int i = 1; i <= n; i ++ ) scanf("%d", &h[i]);
- int tt = 0;
- h[0] = h[n + 1] = -1;
- q[0] = 0;
- for(int i = 1; i <= n; i ++ )
- {
- while(h[i] <= h[q[tt]]) tt --;
- l[i] = q[tt];
- q[++ tt] = i;
- }
-
- tt = 0;
- q[0] = n + 1;
- for(int i = n; i ; i -- )
- {
- while(h[i] <= h[q[tt]]) tt --;
- r[i] = q[tt];
- q[ ++ tt] = i;
- }
-
- LL res = 0;
- for(int i = 1; i <= n; i ++ )
- res = max(res, (LL)h[i] * (r[i] - l[i] - 1));
- cout << res << endl;
- }
- return 0;
- }