Accept: 0 Submit: 0
Time Limit: 1 second Memory Limit : 131072 KB
Problem Description
有一个正整数的数组,化为直方图,求此直方图包含的最大矩形面积。例如 2,1,5,6,2,3,对应的直方图如下:
面积最大的矩形为5,6组成的宽度为2的矩形,面积为10。
Input
第1行:1个数N,表示数组的长度(0 <= N <= 50000)
第2 - N + 1行:数组元素A[i]。(1 <= A[i] <= 10^9)
Output
输出最大的矩形面积
Sample Input
6
2
1
5
6
2
3
Sample Output
10
那么此题的动态规划用在何处呢?
莫急,在我们求解矩形的长时,要计算矩形左边会延伸至何处,右边延伸至何处
显然,这部分不可能每次都遍历一遍,这样复杂度太高
我们要借助之前求得的值来减少访问次数,例如以i位置为起点,向左延伸
首先和i-1位置的高度进行比较,若a[i-1]<a[i],那这矩形已经无法再延伸下去了,所以l[i]=i;
若a[i-1]≥a[i],说明可以延伸下去,而且至少能延伸至l[i-1],为什么呢?
因为a[i-1]能延伸至l[i-1],说明这部分的高度通通都是大于等于a[i-1]的,而a[i-1]≥a[i],所以a[i]也必定可以延伸至l[i-1]
同理,处理出r[i],这样以a[i]作为矩形的宽时,矩形的长为r[i]-l[i]+1
【时间复杂度&&优化】
O(nlogn)
题目链接→51Nod Problem 1102 面积最大的矩形
Code:;
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 50000;
int main(int argc, char const *argv[]){
long long a[maxn];
long long l[maxn], r[maxn];
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
scanf("%lld",a+i);
for (int i = 1; i <= n; ++i){
int k = i - 1;
while(a[k] >= a[i] && k >= 1)
k = l[k] - 1;
l[i] = k + 1;
}
for (int i = n; i >= 1; --i){
int k = i + 1;
while(a[k] >= a[i] && k <= n)
k = r[k] + 1;
r[i] = k - 1;
}
long long ans = 0;
for (int i = 1; i <= n ; ++i)
ans = max(ans,a[i] * (r[i] - l[i] + 1));
printf("%lld\n",ans );
return 0;
}