单调队列——广告印刷

单调队列典型例题——广告印刷  var   h,left,right,p,q:array[0..400000] of longint;   i,n,start,over,max:longint; begin   readln(n);   for i:=1 to n do read(h[i]);   start:=1;   for i:=1 to n do begin     while (over>=st 阅读详情

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

要求输出广告牌的最大面积。


【输入文件】
输入文件 ad.in 中的第一行是一个数n (n<= 400,000)
第二行是n个数,分别表示每个建筑物高度H1,H2…HN,且0<Hi<=1,000,000,000。
【输出文件】
输出文件 ad.out 中一共有一行,表示广告牌的最大面积。
【输入样例】
6
5 8 4 4 8 4
【输出样例】

24


思路:

容易想到,要想使面积最大,肯定要将当前广告覆盖的楼房中,高度最小的那个楼房全部印刷上广告。所以,枚举每个建筑物的高度作为广告矩形的高度,求出在该楼房的左侧,有多少栋连续的楼房的高度大于或等于该楼房的高度,右侧同理。然后得到矩形广告的面积,找出最大面积即可。


枚举法,时间复杂度为O(n^2):

int MaxRectArea(void)
{
	int maxArea = 0;
	int i, j;
	for (i = 0; i < n; i++)
	{
		int count = 1;
		//统计在当前建筑物i的左边,与h[i]相同或更高的建筑物有多少
		for (j = i-1; j >= 0 && h[j] >= h[i]; j--)
		{
			count++;
		}
		//右边同理
		for (j = i+1; j < n && h[j] >= h[i]; j++)
		{
			count++;
		}
		int area = count * h[i];
		if (area > maxArea)
		{
			maxArea = area;
		}
	}
	return maxArea;
}

使用单调队列优化,时间复杂度为O(n):

在这里约定,以当前建筑物为矩形高度,向两侧寻找可以印刷的建筑的过程叫做——扩展。

我们来考察从第i个建筑向左扩展的情况,h数组为建筑物高度,下标为1~n:

如果我们知道,向左扩展到极限时的建筑物的下标为j的话,这时,建筑物j是第一个满足h[j]<h[i]的建筑。那么,第i个建筑物向左扩展的建筑物数量为i-j-1。

如果,对h从左向右建立一个单调递增队列mq,h数组的下标为队列元素,在新的建筑物i要入队时,将队尾所有高度大于等于h[i]的元素都出队,新的队尾mq[rear-1](rear指向队尾的下一个位置)刚好是上面所讲的向左扩展的极限下标j,因为入队顺序是从左向右的,而且在极限下标j与当前建筑下标i之间的这些建筑,因为高度大于等于h[i],所有都出队了,mq[rear-1]就刚好是极限下标j。

向右侧扩展是同样的道理,只需要对h从右向左建立一个单调递增队列即可。

为了简化操作,将h[0]和h[n+1]的值都赋为-1。

下面举一个向左侧扩展的例子:

 

H[]存储建筑物高度,L[]记录向左扩展建筑数量,蓝色代表该建筑已经计算过,红色代表刚刚计算过的建筑物。

     下标    

     0    

     1    

     2    

     3    

     4    

     H[]    

     -1

     9    

     5    

     5    

     -1    

     L[]    

 

 

 

 

 

单调递增队列,front和rear分别为队首和队尾指针,rear指向队尾的下一个位置,初始时让0号建筑入队

     指针    

     Front    

     Rear    

    

    

     队列元素    

     0    

    

    

    

 


1号建筑入队,队尾没有比1号建筑更高的建筑,直接入队,L[1]= 1 - mq[rear-1] - 1,结果如下:

     下标    

     0    

     1    

     2    

     3    

     4    

     H[]    

     -1    

     9    

     5    

     5    

     -1    

     L[]    

 

     0    

 

 

 

 

     指针    

     Front    

 

     Rear    

    

     队列元素    

     0    

     1     

    

    

 


2号建筑入队,队尾元素为1号建筑,高度为9,比2号建筑高,所以出队,新的队尾元素为0号,计算L[2] = 2 –mq[rear-1] – 1,然后2号建筑入队尾,结果如下

     下标    

     0    

     1    

     2    

     3    

     4    

     H[]    

     -1    

     9    

     5    

     5    

     -1    

     L[]    

 

     0    

     1    

 

 

 

     指针    

     Front    

 

     Rear    

    

     队列元素    

     0    

      2     

    

    

 

 

3号建筑入队,队尾元素为2号建筑,高度为5,与3号建筑一样高,所以出队,新的队尾元素为0号,计算L[3] = 3 –mq[rear-1] – 1,然后3号建筑入队尾,结果如下:

     下标    

     0    

     1    

     2    

     3    

     4    

     H[]    

     -1    

     9    

     5    

     5    

     -1    

     L[]    

 

     0    

     1    

     2    

    

 

     指针    

     Front    

 

     Rear    

    

     队列元素    

     0    

     3     

    

    

 

 

最终结果:

     下标    

     0    

     1    

     2    

     3    

     4    

     H[]    

     -1    

     9    

     5    

     5    

     -1    

     L[]    

 

     0    

     1    

     2    

 


代码:

#include <iostream.h>

#define MAXN 1000000

int h[MAXN+5];		//建筑物的高度
int n;				//建筑物的数目

int mq[MAXN+5];		//单调队列,对内元素为建筑物高度的下标
int left[MAXN+5];	//left[i]:在第i个建筑物左侧,不比它的高度小的建筑物数量
int right[MAXN+5];	//right[i]:在第i个建筑物右侧,不比它的高度小的建筑物数量

void CalcLeft(void)
{
	mq[0] = 0;
	int front = 0, rear = 1;
	
	int i;
	for (i = 1; i <= n; i++)
	{
		while (front < rear && h[i] <= h[mq[rear-1]])
		{
			rear--;
		}
		left[i] = i - mq[rear-1] - 1;
		mq[rear++] = i;
	}
}

void CalcRight(void)
{
	mq[0] = n + 1;
	int front = 0, rear = 1;

	int i;
	for (i = n; i >= 1; i--)
	{
		while (front < rear && h[i] <= h[mq[rear-1]])
		{
			rear--;
		}
		right[i] = mq[rear-1] - i - 1;
		mq[rear++] = i;
	}
}

int MaxRectArea(void)
{
	int maxArea = -1;
	int i;
	for (i = 1; i <= n; i++)
	{
		int area = (left[i] + right[i] + 1) * h[i];
		if (area > maxArea)
		{
			maxArea = area;
		}
	}
	return maxArea;
}

int main(void)
{
	while (cin >> n)
	{
		int i;
		for (i = 1; i <= n; i++)
		{
			cin >> h[i];
		}

		h[0] = h[n+1] = -1;
		CalcLeft();
		CalcRight();

		for (i = 1; i <= n; i++)
		{
			cout << left[i] << ' ';
		}
		cout << endl;
		for (i = 1; i <= n; i++)
		{
			cout << right[i] << ' ';
		}
		cout << endl;

		cout << MaxRectArea() << endl;
	}
	return 0;
}

/*
6
5 8 4 4 8 4
6
9 5 8 2 8 8
6
9 6 8 2 8 8
*/

XYNUOJ1561-广告印刷 1561: 广告印刷时间限制: 1 Sec  内存限制: 128 MB提交: 3  解决: 3您该题的状态:已完成[提交][状态][讨论版]题目描述      最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的N个建筑。afy决定在上面找一块尽可能大的矩形放置广告牌。我们假设每个建筑物都有一个高度,从左到右给出每个建筑物的高度H1,H2…HN,且0&lt;Hi&lt;... 阅读详情

相关推荐

STM32实现薄膜压力传感器数据采集(标准库和HAL库实现)

薄膜压力传感器采集压力数据

XiaoCaiDaYong的博客 3万+

广告印刷

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

Welcome to jrxjs's blog! 1753

三菱FX3U PLC红绿灯ST编程实战:从基础逻辑到急停功能完整实现

本文以十字路口红绿灯控制为例,详细讲解了三菱FX3U PLC使用ST编程的完整实战过程。内容涵盖从基础时序逻辑、状态机设计,到急停功能、黄灯闪烁、昼夜模式切换等高级功能的实现,并提供了代码优化与调试技巧,帮助工程师掌握结构化文本在工业控制中的清晰、结构化应用。

weixin_29070861的博客 533

【单调队列】广告印刷

广告印刷 题目描述 最近,afy 决定给 TOJ 印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的 N 个建筑。afy 决定在上面找一块尽可能大的矩形放置广告牌。我们假设每个建筑物都有一个高度,从左到右给出每个建筑物的高度 H1,H2,…,HN,且 0<Hi≤1,000,000,000,并且我们假设每...

ETO的博客 2074

TI DSP从COFF切换到EABI输出格式的5个关键修改点(TMS320F280025实测)

本文基于TMS320F280025实测,详细解析了TI DSP从COFF切换到EABI输出格式的5个关键修改点。核心差异在于EABI遵循ELF标准,涉及链接器优化、RAM数据共享、工具链升级、double数据类型位宽变化及链接器命令文件重构。迁移时需使用.retain指令防止关键数据被优化,利用NOINIT段保护共享RAM,并更新hex2000等工具,以确保BootLoader与应用程序稳定运行。

weixin_29189381的博客 265

UG\NX二次开发 分割曲线

分割曲线没有ufun函数?那就换一种思路实现。

王牌飞行员_里海的博客 1144

广告印刷 题解(单调队列)

题目描述       最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的N个建筑。afy决定在上面找一块尽可能大的矩形放置广告牌。我们假设每个建筑物都有一个高度,从左到右给出每个建筑物的高度H1,H2…HN,且0 输入 中的第一行是一个数n (n 第二行是n个数,分别表示每个建筑物高度H1,H2…HN,且0 输出 输出文件 ad.out 中一共有一行,

persist 1957

【AI智能体】Claude Code 高级编程技巧实战项目详解

Claude Code 高级编程技巧实战项目详解

congge 1万+

单调队列+单调栈(stl使用结合)

广告印刷(模板题) Description 最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的NN个建筑。afy决定在上面找一块尽可能大的矩形放置广告牌。我们假设每个建筑物都有一个高度,从左到右给出每个建筑物的高度H1,H2…HNH1,H2…HN,且0<Hi≤1,000,000,0000<Hi≤1,000,000,000,并且我们假设每个建筑物的宽度均为1。要求输出广告牌的最大面积。 Input 第一行是一个数nn(n≤400,000n≤400,000)..

zheng159987的博客 973

【WRFDA教程第四期】雷达数据同化(Radar Data Assimilation)

雷达数据同化(Radar Data Assimilation)

WW、forever的博客 1758

向华为学习——解读华为战略规划SP与业务计划BP流程【附全文阅读】

该方案针对大中型企业高管及战略团队,系统拆解华为SP(4-9月中长期规划)与BP(10-12月年度执行)双轨体系,形成"战略制定-业务设计-资源配置-绩效解码"闭环。SP侧重市场趋势分析、业务优先级与资源分配,BP细化KPI、预算及行动计划。通过价值树、战略解码等工具实现战略到部门/个人的目标分解,强化跨部门协同与过程管控。配套17份华为实战资料(包括战略管理、流程优化、销售组织建设等核心方法论),助力企业建立规范的战略执行体系,实现资源优化与绩效落地。

cdfunlove的博客 767

NKOJ 2150 广告印刷 单调队列

【单调队列】广告印刷 Time Limit:10000MS  Memory Limit:65536K Total Submit:296 Accepted:108  Case Time Limit:1000MS Description 最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的N(N Input 第一行,一个整数N  第二行,N个空格间隔的整数,

MY Blog 1539

OKX 欧易 交易机器人开发基础

接口文档: https://www.okx.com/docs-v5/zh/#overview REST API 常用请求 查看账户余额 结果数据格式: 获取限价 结果格式: 获取指数行情 数据结构: 下单 结果数据: 获取未成交订单列表 返回结果: 撤单 结果结构:

Willin Wang 的全栈升级指南 2万+

NKOJ 2150 【单调队列】广告印刷

输出用cout,不然用lld和I64d都会wa。 对于每一个建筑物,要知道往左到哪一个建筑第一个高度比它低,知道往右走哪一个建筑物第一个高度比它低。 可以用dp,也可以用单调队列。 首先从左往右,构造单增队列,这样始终有一个最小值,每加入一个高度h,先把队尾处大于等于它的高度全部删掉。 因为后面的高度,如果高度比h大,那么找到h就停止了,如果高度 如果队列空了,证明h是从1开始到ind[

便纵有千种风情 1467

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

单调队列练习之广告印刷

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

weixin_30835649的博客 234

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【广告印刷】单调队列

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

weixin_30824599的博客 318

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【例题】【单调队列】NKOJ2150 广告印刷

NKOJ2150 广告印刷 时间限制 : 10000 MS 空间限制 : 65536 KB问题描述 最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的N(N<=400000)个建筑。afy决定在上面找一块尽可能大的矩形放置广告牌。我们假设每个建筑物都有一个高度,从左到右给出每个建筑物的高度H1,H2…HN,0<=Hi<=1,000,000并且我们假设每个建筑物

ANG 1010

单调队列之广告印刷问题

问题:有n幢建筑,其高度分别为H1,...,Hn,其宽度为1,且这些建筑紧靠在一起,当前需要在这些建筑上刷一个非常大的矩形广告,求矩形广告的最大值。   先翻译成数学题,给定n个正数的序列,定义区间值A(i,j)= Min(Hi,Hi+1,..,Hj) * (j-i+1),求所有区间值的最大值。这个问题网上都有答案,无奈答案一律都相当简单,个人实在无法理解,故成此文! (1) 最简单

白水白水的专栏 2071

浅析单调队列

浅析单调队列 By 钟桓  9月 16 2014 更新日期:9月 16 2014 文章目录 1. 简单的单调队列的应用: 1.1. 1.果子合并问题1.2. Window 1.2.1. poj2823 1.3. 广告印刷 2. 单调队列在动态规划中的应用3. 参考资料: 大家应该了解什么是队列,那么在队列前面加上“单调”,意思也是显而易见的,就是这个队列是从前

ZH de 部落格 4782

191103-单调队列练习

191103-单调队列练习 T1 志愿者选拔 题目描述 解析 题解 #include<bits/stdc++.h> #define M 1000009 using namespace std; int tot,tail,head,last,T,x,tim[M],q[M]; char s[100],s1[100]; int main() { freopen("select.in",...

Daniel__d的博客 308

单调队列 及其应用

单调队列及其应用 关键字  转自http://www.cnblogs.com/liukeke/archive/2011/07/31/2122488.html 队列,合并果子,窗户,广告印刷,最长XX子序列,志愿者选拔,动态规划,烽火传递 正文 单调队列,望文生义,就是指队列中的元素是单调的。如:{a1,a2,a3,a4……an}满足a1序列便是单调递增序列。同理递减队列也是存在的。 单调

Stay hungry,stay foolish! 940

单调队列及其应用

  单调队列即队列内元素单调递增或递减,删除数据可以在队头或者队尾,加入元素只能在队尾加入。  由于单调队列的队头一定是最小值,故查询为O(1);每个元素最多进队一次,出队一次,摊排分析下来仍然是O(1).   例1. 广告印刷【问题描述】最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的N(N&lt;=400000)个建筑。afy决定在上面找一块尽可能大的矩形放...

yangzhongmin21的专栏 254

uva 1506 Largest Rectangle in a Histogram

Largest Rectangle in a Histogram http://acm.hdu.edu.cn/showproblem.php?pid=1506 Time Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others) Problem Description A histogram ...

weixin_30487317的博客 145

在单调的队列

浅析单调队列 By钟桓 9月 16 2014更新日期:9月 16 2014 文章文件夹 1.简单的单调队列的应用: 1.1.1.果子合并问题1.2.Window 1.2.1.poj2823 1.3.广告印刷 2.单调队列在动态规划中的应用3.參考资料: 大家应该了解什么是队列,那么在队列前面加上“单调”。意思也是显而易见的。就是这个...

weixin_30399055的博客 74
上一篇: 优先队列——合并果子
下一篇: 单调队列—— HDU 4193 Non-negative Partial Sums
庞老板
博客等级 码龄15年 127粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

庞老板

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值