AcWing 直方图中最大的矩形
题目:
- 有图。转链接
题解:
- 单调栈。
学OI二年了才去学这道经典题… …- 一种朴素做法就是每次以当前矩形的高为高,然后往左右两边找到第一个高度比自己小的矩形(也就是找到了左右边界),然后当前答案就是当前矩形高度 * (找到的右边界 - 找到的左边界 + 1)。最终答案就是在所有当前答案里取max。
- 复杂度O(n^2),问题出在拓展边界这一步上。可以这样思考,如果当前矩形的高度<=前面的一个矩形,那么前面的一个矩形我可以直接删除它,因为下一次找第一个高度小于某矩形的时候,肯定会找到当前矩形而不会找到前面的一个矩形。
- 进一步把刚才的思路抽象,就是以下流程:
- 建一个栈
- 对于当前矩形,只要栈的top>=当前矩形高度,就pop掉,直到top<当前矩形高度。那么top矩形的位置就是当前矩形所要找的左边界。
- 插入当前矩形
那么找右边界同理。
这样每个矩形只被访问到了一遍,复杂度为O(n),挺不错的!
#include <iostream>
#include <cstdio>
#include <stack>
#define N 100005
#define inf 0x7fffffff
#define int long long
using namespace std;
struct Node {int val, pos;};
int n, ans;
int a[N], l[N], r[N];
int read()
{
int x = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
return x;
}
signed main()
{
while(scanf("%lld", &n) == 1)
{
if(!n) break;
stack<Node> stk1; stk1.push((Node){-inf, 0});
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i <= n; i++)
{
while(stk1.top().val >= a[i]) stk1.pop();
l[i] = stk1.top().pos + 1;
stk1.push((Node){a[i], i});
}
stack<Node> stk2; stk2.push((Node){-inf, n + 1});
for(int i = n; i >= 1; i--)
{
while(stk2.top().val >= a[i]) stk2.pop();
r[i] = stk2.top().pos - 1;
stk2.push((Node){a[i], i});
}
ans = -inf;
for(int i = 1; i <= n; i++) ans = max(ans, a[i] * (r[i] - l[i] + 1));
printf("%lld\n", ans);
}
return 0;
}