题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1506
我们要求图中长方形最大面积,我们都知道长方形的面积等于长×宽,那怎么选择长和宽呢?我们的思路是这样子的:我们遍历数组,将当前位置上条形的高度作为长方形的宽,然后向左向右延伸,求出以当前高度能够扩展到的最左端和最右端的位置,确定长方形的长度。最后在这些长方形面积中取一个最大值就行了。
但是这样有一个问题,题目中n的范围(即条形个数)在1e5以内,如果遇到最坏的情况:所有条形高度相同时,时间复杂度就到了1e10.
所以这里我们需要优化一下,我们要在更短的时间内找到长方形的左右端点,以找左端点为例。样例中,我们知道第四号位上的条形能延伸到第三位(这里有一个特点,能够延伸出去的这段距离上的条形高度肯定是大于等于当前条形高度的)。接着我们来看第五号位上的条形,它的高度为1,向左遍历会发现它左边的条形高度为4 1,所以左边条形能够遍历到的地方,1肯定也能遍历到。
所以我们可以设一个数组,存下相应位置上条形能够遍历到最左/右端点,方便优化之后左右端点的查询。
查询左端点:
for(int i=2; i<=n; i++)
{
while(dp1[i]-1>=1&&high[i]<=high[dp1[i]-1])
dp1[i]=dp1[dp1[i]-1];
}
题目代码:
#include <iostream>
#include <string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<set>
#include<vector>
typedef long long LL;
using namespace std;
#define chl (root<<1)
#define chr ((root<<1)|1)
#define mid ((l+r)>>1)
const LL INF=2e9;
const int manx=1e5+10;
LL n,l,r,high[manx],dp1[manx],dp2[manx];
int main()
{
while(scanf("%lld",&n),n)
{
LL ans=0;
for(int i=1; i<=n; i++)
{
scanf("%lld",&high[i]);
dp1[i]=i;
dp2[i]=i;
}
for(int i=2; i<=n; i++)
{
while(dp1[i]-1>=1&&high[i]<=high[dp1[i]-1])
dp1[i]=dp1[dp1[i]-1];
}
for(int i=n-1; i>=1; i--)
{
while(dp2[i]+1<=n&&high[i]<=high[dp2[i]+1])
dp2[i]=dp2[dp2[i]+1];
}
for(int i=1; i<=n; i++)
{
dp2[i]-=dp1[i]-1;
ans=max(high[i]*dp2[i],ans);
}
printf("%lld\n",ans);
}
}
听完题解后才发现,可能这才是学到了dp的精髓吧
变型例题:Largest Rectangle
注意高度为0是其实可以不用遍历了