题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=258
解题思路:求最大长方形面积,就是求某一个高度和这个高度最大连续长度的乘积。
自己的思路是对每一个高度从下往上扫描,对每一个高度利用分治的思想求得这个高度的最大连续长度(大于等于这个高度),可惜超时了,但是这种思想还是有用的,毕竟是之前书上看到的,虽然忘了……
分治思路:对于一个区间来说,最大连续长度在取区间左半部、右半部和中部的最大连续长度。
下面是我的代码:
#include<stdio.h>
#include<algorithm>
using namespace std;
int n, len;
long long mx;
int hist[100005];
int hight[100005];
int search(int b, int e, int h) {
if(b == e) return 1;
int mid = b+(e-b)/2;
int k, max, len = 0;
int llen = search(b, mid, h);
int rlen = search(mid+1, e, h);
k = mid;
while(hist[k--] >= h) len++;
k = mid+1;
while(hist[k++] >= h) len++;
if(llen > rlen) max = llen;
else max = rlen;
return max>len?max:len;
}
int main() {
// freopen("data.in", "r", stdin);
int len1, len2;
while(scanf("%d", &n) && n) {
for(int i = 0; i < n; i++) {
scanf("%d", &hist[i]);
hight[i] = hist[i];
}
mx = -(1<<30);
sort(hight, hight+n);
len = unique(hight, hight+n)-hight;
for(int i = 0; i < len; i++) {
int ll = search(0, n, hight[i]);
if(mx < hight[i]*ll) {
mx = hight[i]*ll;
}
}
printf("%d\n", mx);
}
return 0;
}
下面说一下最优代码的思路——单调队列!!!使用一个长度栈和高度栈记录这个高度的当前最长连续上升序列。
边输入边处理。实现上,长度栈存储高度栈相应位置当前的最大连续长度,每计算一次面积就会计算最大连续长度,然后更新长度。注意到,一旦遇到高度变低的情况,说明前面高度大于等于当前高度的部分全部失效——大于等于当前高度的只在当前高度面积的计算时有效,之后就不是连续的了。计算过程中会将前面大于等于这个高度的高度全部出栈,只留下小于当前高度的部分,只有这部分在后面的连续长度计算有效,
具体过程如下:
如果最新输入的高度比高度栈顶大的话,就进行压栈操作,并且把长度1压栈;否则的话,计算一次这个高度的当前最大面积,方法是不断的累加长度计算新的最大面积并进行出栈操作直到栈顶元素小于这个高度,最后将这个高度再次压栈,并且把当前将这个高度的对应当前最大连续长度也压入高度栈,保证高度栈和长度栈的一一对应关系。
最优代码如下:
#include<cstdio>
#include<iostream>
using namespace std;
int stack[100010]={-2},len[100010];
long long ans;
int main() {
int n,top,h;
while(scanf("%d",&n), n) {
top=0;ans=0;
for(int i=0;i<=n;i++) { //注意是小于等n,相当于多循环一次
if(i<n)scanf("%d",&h);
else h=-1; //这个-1是为了最后保证最后一个高度也会被计算
if(h > stack[top]) {
stack[++top]=h;
len[top]=1;
} else {
int l = 0;
while(stack[top] >= h) {
ans=max(ans,(long long)(l+len[top])*stack[top]);
l += len[top--]; //累加最大连续长度
}
stack[++top] = h; //当前高度压栈
len[top] = l + 1; //更新该高度最大连续长度
}
}
printf("%lld\n",ans); //使用long long类型以防面积溢出int类型
}
return 0;
}