A - Largest Rectangle in a Histogram(直方图中最大的矩形)

A - Largest Rectangle in a Histogram

A histogram(直方图)is a polygon(多边形) composed of a sequence of rectangles(矩形) aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:

Usually, histograms are used to represent discrete distributions(离散分布), e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.
Input
The input contains several test cases. Each test case describes a histogram and starts with an integer n, denoting the number of rectangles it is composed of. You may assume that 1<=n<=100000. Then follow n integers h1,...,hn, where 0<=hi<=1000000000. These numbers denote the heights of the rectangles of the histogram in left-to-right order. The width of each rectangle is 1. A zero follows the input for the last test case.
Output
For each test case output on a single line the area of the largest rectangle in the specified histogram. Remember that this rectangle must be aligned at the common base line.
Sample
Inputcopy
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Output
8
4000
Hint
Huge input, scanf is recommended.

题意

找出直方图中最大的矩形

暴力做法

\(o(n)\) -> tle

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;

#define X first
#define Y second

typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e5+10;
const int M = 2e5+10;
int n,m;
int a[N],st[N],tt;
LL ans;

void solve(){
	while(1){
		ans = 0;
		tt = 0;
		cin >> n;
		if(n == 0)break;
		for(int i = 1; i <= n; i ++)cin >> a[i];
		for(int i = 1; i <= n; i ++){
			int l = i;
			while(l && a[l - 1] >= a[i])l --;
			int r = i;
			while(r < n && a[r + 1] >= a[i])r ++;
			ans = max(ans,(LL)a[i] * (r - l + 1));
		}
		cout << ans << nl;
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	solve();
}

优化

暴力做法的思路是枚举每一个矩形,找到左边最后一个大于等于这个矩形高度的矩形标记下标为\(l_i\),再找到左边最后一个大于等于这个矩形高度的矩形标记下标为\(r\)
那么答案为

\[max(a_i\cdot(r_i-l_i)) \]

image
转化->
左边最后一个大于等于这个矩形高度的矩形下标 \(=\) 左边第一个小于这个矩形高度的矩形下标+1
右边最后一个大于等于这个矩形高度的矩形下标 \(=\) 右边第一个小于这个矩形高度的矩形下标-1
因此我们可以联想到单调栈(复杂度\(o(n)\))优化得到两个下标

代码

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;

#define X first
#define Y second

typedef pair<int,int> pii;
typedef long long LL;
const char nl = '\n';
const int N = 1e5+10;
const int M = 2e5+10;
int n,m;
int h[N],st[N],tt,l[N],r[N];
LL ans;

void init(){
	ans = 0;
	tt = 0;
}

void solve(){
	while(1){
		init();
		cin >> n;
		if(n == 0)break;
		for(int i = 1; i <= n; i ++)cin >> h[i];
		st[0] = 0;
		for(int i = 1; i <= n; i ++){
			while(tt && h[i] <= h[st[tt]])tt --;
			l[i] = st[tt] + 1;
			st[++ tt] = i;
		}
		tt = 0;
		st[0] = n + 1;
		for(int i = n; i; i -- ){
			while(tt && h[i] <= h[st[tt]])tt --;
			r[i] = st[tt] - 1;
			st[++ tt] = i;
		}
		for(int i = 1; i <= n; i ++ ){
		
			ans = max(ans,(LL)h[i] * (r[i] - l[i] + 1));
		}
		cout << ans << nl;
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	solve();
}
posted @ 2023-02-22 21:17  Keith-  阅读(19)  评论(0编辑  收藏  举报