2019牛客暑期多校训练营(第三场)----F-Planting Trees

本文介绍如何使用单调队列解决一个特定的矩阵问题,该问题要求在矩阵中找到满足最大值与最小值之差不超过给定阈值的子矩阵,且要求子矩阵的面积尽可能大。文章详细解释了算法的思路,包括如何通过两次遍历确定矩阵的上下边界,以及如何利用单调队列动态获取每列的最大值和最小值,最终确定子矩阵的左右边界。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先发出题目链接:
链接:https://ac.nowcoder.com/acm/contest/883/F
来源:牛客网
涉及:单调队列

点击这里回到2019牛客暑期多校训练营解题—目录贴


题目如下
在这里插入图片描述
在这里插入图片描述
题目有个细节提示:保证所有情况下的 N 3 N^3 N3 之和不超过 25 ∗ 1 0 7 25*10^7 25107,说明我们需要构造一个 N 3 N^3 N3 的算法。

可以很快想到。 N 2 N^2 N2 的复杂度来确定我们考虑的矩形的上下界,即每次找满足条件的最大矩阵的时候,我们就已经知道这个矩阵的上边界和下边界分别位于整个矩阵的第几行。

即获得一个当前考虑的区域

for(int i = 1; i <= n; i++){//i为上边界
	for(int j = i; j <= n; j++){//j为下边界
		...(求解当前确定边界的最大矩阵)
	}
}

知道上下边界之后,开始求解当前上下边界的最大矩阵

题目所说一个矩阵必须满足最大值与最小值之差不超过 M M M,所以在确定上下界的同时,还要动态的获得当前上下界已确定的目标区域矩阵中的每一列的最大值和最小值

两个数组 m a [ m a x n ] ma[maxn] ma[maxn] m i [ m a x n ] mi[maxn] mi[maxn] 来存当前考虑区域的每一列的最大值和最小值

for(int i = 1; i <= n; i++){//i为上边界
	memset(ma, 0, sizeof(ma));//初始化ma数组
	memset(mi, 0x3f3f3f, sizeof(mi));//初始化mi数组
	for(int j = i; j <= n; j++){//j为下边界
		for(int k = 1; k <= n; k++){//动态求解每一列得到最大值
			ma[k] = max(ma[k], a[j][k]);
			mi[k] = min(mi[k], a[j][k]);
		}
		...(求解当前确定边界的最大矩阵)
	}
}

上面操作相当于把多行矩阵中的非最值给忽略,留下来的是单行的最大值矩阵和最小值矩阵

举个例子:
在这里插入图片描述


有了每列最大值矩阵和最小值矩阵,然后就要确定最大矩阵的左右边界。

可以用单调队列来实现,于是就变成了单调队列经典例题

用两个单调队列,一个单调递减队列维护 m a ma ma 数组,一个单调递增队列维护 m i mi mi 数组。

注意单调队列维护的是两个数组得到下标而不是值。每次加入一个值就判断单调递减队列的最大值(队列首元素)与单调递增队列的最小值(队列首元素)之差是否大于 M M M,如果大于 M M M 就要将队列首元素出队列。

最后判断当前区域的最大矩阵的面积与当前已经求得的最大面积矩阵哪个更大。

int que[3][maxn]; //单调队列
int l = 1;//最大矩阵左边界
int l1= 1, r1 = 0;//单调递减队列在que数组内的左边界与右边界
int l2 = 1, r2 = 0;//单调递增队列在que数组内的左边界与右边界
for(int r = 1; r <= n; r++){//求当前左边界能往右延伸多远
	while(l1 <= r1 && ma[r] > ma[que[0][r1]])	r1--;//先将队列内的非有序元素弹出
	que[0][++r1] = r;//放入当前元素
	while(l2 <= r2 && mi[r] < mi[que[1][r2]])	r2--;//先将队列内的非有序元素弹出
	que[1][++r2] = r;//放入当前元素	
	while(l <= r && ma[que[0][l1]]-mi[que[1][l2]] > p){//判断当前延伸的长度是否合法(之差是否大于M)下面是不合法的处理
		l++;//左边界往右走
		while(que[0][l1] < l && l1 <= r1)	l1++;//队列弹出比l左边界还要靠左的元素(这些元素已经不用再考虑了)
		while(que[1][l2] < l && l2 <= r2)	l2++;//队列弹出比l左边界还要靠左的元素(这些元素已经不用再考虑了)
	}
	ans = max(ans, (j-i+1)*(r-l+1));//比较答案
}

代码如下

#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 505;
int a[maxn][maxn], t, n, p;//题目所给变量
int ma[maxn], mi[maxn];//上下边界所确定的区域的每列最大值及最小值
int que[3][maxn]; //两个单调队列
int main(){
	cin >> t;
	while(t--){
		int ans = 0;//答案
		scanf("%d%d", &n, &p);
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				scanf("%d", &a[i][j]);
			}
		}
		for(int i = 1; i <= n; i++){//i为上边界
			memset(ma, 0, sizeof(ma));//初始化ma数组
			memset(mi, 0x3f3f3f, sizeof(mi));//初始化mi数组
			for(int j = i; j <= n; j++){//j为下边界
				for(int k = 1; k <= n; k++){//动态求解每一列得到最大值
					ma[k] = max(ma[k], a[j][k]);
					mi[k] = min(mi[k], a[j][k]);
				}
				int l = 1;//最大矩阵左边界
				int l1 = 1, r1 = 0;//单调递减队列在que数组内的左边界与右边界
				int l2 = 1, r2 = 0;//单调递增队列在que数组内的左边界与右边界
				for(int r = 1; r <= n; r++){//求当前左边界能往右延伸多远
					while(l1 <= r1 && ma[r] > ma[que[0][r1]])	r1--;//先将队列内的非有序元素弹出
					que[0][++r1] = r;//放入当前元素
					while(l2 <= r2 && mi[r] < mi[que[1][r2]])	r2--;//先将队列内的非有序元素弹出
					que[1][++r2] = r;	//放入当前元素		
					while(l <= r && ma[que[0][l1]]-mi[que[1][l2]] > p){//判断当前延伸的长度是否合法(之差是否大于M)下面是不合法的处理
						l++;//左边界往右走
						while(que[0][l1] < l && l1 <= r1)	l1++;//队列弹出比l左边界还要靠左的元素(这些元素已经不用再考虑了)
						while(que[1][l2] < l && l2 <= r2)	l2++;//队列弹出比l左边界还要靠左的元素(这些元素已经不用再考虑了)
					}
					ans = max(ans, (j-i+1)*(r-l+1));//比较答案
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
} 
内容概要:本报告探讨了AI赋能汽车行业智能化转型的技术创新,涵盖了研发设计智能化、用户运营智能化和座舱体验智能化三大核心场景。通过解析智己汽车的实践,展示了AI在压缩研发周期、提升销售转化率和优化座舱体验等方面的实际价值。报告指出,AI技术正深刻改变汽车产业的价值链,推动从“机械制造”向“移动智能体”的转变,并提出了未来汽车行业智能化的发展趋势,包括更个性化的用户体验、跨产业融合以及数据安全和隐私保护的重要性。 适合人群:汽车行业从业者、技术研发人员、市场营销人员、政策制定者及相关领域的研究者。 使用场景及目标:①理解AI技术在汽车研发设计中的应用,如生成式设计、仿真优化和智能测试;②掌握AI在用户运营中的应用,如智能内容生成、销售辅助和数据闭环优化;③了解AI在座舱体验中的应用,如意图服务编排、情感计算和端到端语音链路优化;④探讨未来汽车行业智能化的发展方向,包括个性化服务、产业融合和数据安全。 其他说明:本报告不仅提供了理论和技术层面的分析,还结合了具体的落地实践案例,为企业在智能化转型过程中提供了可复用的AI赋能框架。报告强调了政策支持、技术创新和产业协同在推动汽车行业智能化转型中的重要作用,旨在为行业提供有价值的参考和指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值