[HDU 1506 Largest Rectangle in a Histogram] ...类dp?...

15 篇文章 0 订阅

题目链接  http://acm.hdu.edu.cn/showproblem.php?pid=1506

Largest Rectangle in a Histogram

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 14310    Accepted Submission(s): 4104


Problem Description
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 Input
  
  
7 2 1 4 5 1 3 3 4 1000 1000 1000 1000 0
 

Sample Output
  
  
8 4000
 

Source
University of Ulm Local Contest 2003
 
题目是让你求最大矩阵面积
n<10w,看得出这题是不能暴力的,想来想去,就是已知出当前第i根柱子,从第i根柱子出发,往左往右,求出连续的,并且都比第i根柱子长的柱子根数
刚开始一直纠结于根数的求法, 如果每个i都往左往右暴力枚举,那必然TLE,可是又想不出其他的方法,苦苦思索后换了一个思考角度,求出第i根柱子往左/右,比它高的那根最左/右边的柱子的下标,到时候相减一下就能得出他们的根数了,也就是宽度。答案就是宽度*第i根柱子的高。
求下标的方法是记录祖先点,用l[n],r[n]分别记录当前柱子的左祖先点和右祖先点。例如样例
 2145133
   l1134166
   r1744777
如果不取祖先点而是遍历,TLE无误
代码如下
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXM 100010
int n;
long long mx, s[MAXM], l[MAXM], r[MAXM];
int main()
{
//	freopen("input.txt", "r", stdin);
	while (scanf("%d", &n) != EOF)
	{
		if (!n)
			break;
		for (int i = 1; i <= n; i++)
			scanf("%lld", &s[i]);
		l[1] = 1;
		r[n] = n;
		int id;
		for (int i = 2; i <= n; i++)
		{
			id = i;
			while (id > 1 && s[i] <= s[id - 1])  //如果id未到边界,并且当前柱子的高度小于等于前一根柱子的高度
				id = l[id - 1];    //取前一根柱子的祖先点,也就是比前一根柱子还要高的柱子的下标
			l[i] = id;   //记录下比当前柱子高的,最左边的那根柱子的下标,也就是得出了当前柱子的祖先点
		}
		for (int i = n - 1; i >= 1; i--)   //当前柱子的右边  同上
		{
			id = i;
			while (id < n && s[i] <= s[id + 1])
				id = r[id + 1];
			r[i] = id;
		}
		mx = -1;
		for (int i = 1; i <= n; i++)
			mx = max(mx, (r[i] - l[i] + 1)*s[i]);   //计算面积,遍历一边即可,取最大值
		printf("%lld\n", mx);
	}
	return 0;
}

若实在想不出计算方式,何不换位思考另辟蹊径呢?


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值