
第1行:1个数N,表示数组的长度(0 <= N <= 50000) 第2 - N + 1行:数组元素A[i]。(1 <= A[i] <= 10^9)
输出最大的矩形面积
6 2 1 5 6 2 3
10
这题基本跟hdu-1506一样,就是细节有点不同。
首先该问题可以用dp解决,预处理出每一个点能够向两边延伸的距离,向左找到第一个比当前点高度小的下标记为i,向右找到第一个比当前点高度小的下标记为j,那么此时以这点高度的最大值是f[i]*(j-i+1); 然后用for循环扫一遍求出最大值即可。解题关键在于求出每一个点的边界。
#include<cstdio>
const int N = 100010;
__int64 f[N],l[N],r[N],sum;
int main()
{
int n,i;
while(scanf("%d",&n)!=EOF&&n)
{
sum=0;
for(i=1;i<=n;i++)
{
scanf("%I64d",&f[i]);
l[i]=r[i]=i; //初始i点的左边界和右边界都是i。
}
f[0]=f[n+1]=-1;
for(i=1;i<=n;i++)
{ //预处理左边界
while(f[i]<=f[l[i]-1])
l[i]=l[l[i]-1];
}
for(i=n;i>=1;i--)
{ //预处理右边界
while(f[i]<=f[r[i]+1])
r[i]=r[r[i]+1];
}
for(i=1;i<=n;i++) //遍历更新最大值
if(f[i]*(r[i]-l[i]+1)>sum)
sum=f[i]*(r[i]-l[i]+1);
printf("%I64d\n",sum);
}
return 0;
}
然后还可以利用单调栈解决,这里维护一个单调递减栈,首先如果栈空或者比栈顶元素大的数的下标直接加入栈中,如果与栈顶元素相等可以不用处理, 如果比栈顶元素小,那么需要不断更新栈顶元素,并且更新面积,一直到栈顶元素小于当前元素为止。把f[n]=-1,这样可以把栈中所有元素算完。
比如样例 2,1,5,6,2,3 首先将2入栈,因为1比2小,那么就把栈中元素的最大面积算出来,就是2,并且弹栈,保存退栈的元素下标,就是0,然后赋值f[0]=1,因为1可以延伸到第一个,那么加入栈中的下标是0,并且f[0]=1,遇到5,6都是直接加入栈中,遇到2,当前栈顶元素是6,所以算出6这点的面积,并且保存下标,此时栈顶元素是5,那么算出面积是10,sum = (i-q.top())*f[q.top()]; 因为i跟q.top隔了2,然后保存2的下标并且赋值为2,表示2这点可以向前延伸的最长距离,遇到3直接加入,然后遇到-1,算出每一个点能表示的最大面积。
#include<cstdio>
#include<stack>
using namespace std;
__int64 f[50010];
int main()
{
int n,i,ans;
__int64 temp,sum=0;
stack<int>s;
scanf("%d",&n);
while(!s.empty()) s.pop();
for(i=0;i<n;i++)
scanf("%I64d",&f[i]);
f[n]=-1;
for(i=0;i<=n;i++)
{
if(s.empty()||f[i]>f[s.top()])
{
s.push(i);
}
else if(f[i]<f[s.top()])
{
while(!s.empty()&&f[i]<f[s.top()])
{
temp=(i-s.top())*f[s.top()];
if(temp>sum) sum=temp;
ans=s.top();
s.pop();
}
s.push(ans);
f[ans]=f[i];
}
}
printf("%I64d\n",sum);
return 0;
}