广告印刷

Description

最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的N(N<=400000)个建筑。afy决定在上面找一块尽可能大的矩形放置广告牌。我们假设每个建筑物都有一个高度,从左到右给出每个建筑物的高度H1,H2…HN,0<Hi<=1,000,000并且我们假设每个建筑物的宽度均为1。要求输出广告牌的最大面积。

Input

第一行,一个整数N
第二行,N个空格间隔的整数,表示从左往右每栋楼的高度

Output

一个整数,表示最大面积

Sample Input

6
5 8 4 4 8 4

Sample Output

24

【分析】

        定义两个数组l[maxn],r[maxn]分别表示当前节点可以向左右扩展的最大长度。这个长度的要求是左边(右边)连续的不小于当前节点高度的最大区间长度。

        如样例的r便是:r[1]=2;r[2]=1;r[3]=4;r[4]=3;r[5]=1;r[6]=1;现在便是想怎样求得r和l数组。一个最朴素的想法便是枚举每个i然后往右边扫。显然时间复杂度为O(n^2)。不满足数据范围。

        可以用单调队列优化。从原序列中依次取出元素插入单调队列。若插入位置为tail,则需满足h[i]>=Q[tail-1]。若不满足,则tail向前移动,继续判断,直到满足为止。很明显,tail向前移动的过程,其实就是元素从队尾出队的过程。注意,在某个元素出队的同时,记下他的r值。用Qr数组记录Q数组中元素下标。那么,r[Qr[tail-1]]=i-Qr[tail-1]。这里i是当前要插入的元素下标,tail-1是要被删除的元素。

        最后,答案ans=max{(r[i]+l[i]-1)*h[i]};

 

【代码】
 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500005;
long long N,v[maxn],Q[maxn],Qr[maxn],t[maxn];
long long l[maxn],r[maxn];
long long ans=0;
void _in(long long &x)
{
	char t=getchar();
	while(t<'0'||'9'<t) t=getchar();
	for(x=t-'0',t=getchar();'0'<=t&&t<='9';x=x*10+t-'0',t=getchar());
}
void _init()
{
	_in(N);
	ans=0;
	for(int i=1;i<=N;i++)
	    _in(v[i]);
}
void _solve()
{
	v[0]=-0x7FFFFFFF;
	v[N+1]=-0x7FFFFFFF;
	int head=1,tail=2;
	Q[head]=v[1];
	Qr[head]=1;
	for(int i=2;i<=N+1;i++)
	{
		if(v[i]>=Q[tail-1])
		{
			Qr[tail]=i;
		    Q[tail++]=v[i];
		}
		else
		{
			while(v[i]<Q[tail-1]&&tail!=head)
			{
			    tail--;
			    r[Qr[tail]]=i-Qr[tail];
			}
			Q[tail]=v[i];
			Qr[tail]=i;
			tail++;
		}
	}
	memset(Q,0,sizeof(Q));
	memset(Qr,0,sizeof(Qr));
	memcpy(t,v,sizeof(v));
	for(int i=0,j=N+1;i<=N+1;i++,j--)
	    v[i]=t[j];
	head=1,tail=2;
	Q[head]=v[1];
	Qr[head]=1;
	for(int i=2;i<=N+1;i++)
	{
		if(v[i]>=Q[tail-1])
		{
			Qr[tail]=i;
		    Q[tail++]=v[i];
		}
		else
		{
			while(v[i]<Q[tail-1]&&tail!=head)
			{
			    tail--;
			    l[Qr[tail]]=i-Qr[tail];
			}
			Q[tail]=v[i];
			Qr[tail]=i;
			tail++;
		}
	}
	memcpy(v,t,sizeof(t));
	memcpy(t,l,sizeof(l));
	for(int i=0,j=N+1;i<=N+1;i++,j--)
	    l[i]=t[j];
	for(int i=1;i<=N;i++)
	{
		long long temp=(r[i]+l[i]-1)*v[i];
		ans=max(ans,temp);
	}
	printf("%I64d\n",ans);
}
int main()
{
    _init();
	_solve();
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值