刷题刷到第1577题的时候,我愣了一下——铺地毯?这不就是按顺序往地板上盖毯子,最后问某个点被哪张毯子盖住吗?听起来像模拟题,可真动手写的时候,四面八方都能踩坑。这道题在蓝桥杯的"算法提高VIP"题库里,实际上是把一个很经典的“区间覆盖 + 点查询”问题包装成了生活场景,考的不是你会不会铺地毯,而是你会不会倒着想问题。
先说结论:这道题的最优解非常简单,思路顺过来以后代码不超过二十行,但如果你顺着“铺地毯”这个动词去模拟,很容易掉进二维数组和超时的坑里。这篇文章我会从题面解读开始,一步步讲清楚为什么暴力模拟不行、倒序查找为什么是对的、C++和Python分别怎么写,还会延展一下如果题目改成“多个查询点”该怎么办。无论你是刚开始备战蓝桥杯,还是想借这道题补一补逆向思维,都可以放心往下看。
1. 读完题面先别动手:数据范围已经告诉你该用哪种思路
1.1 题面到底在问什么
这道题的场景很直白:会场地上要铺若干张矩形地毯,编号从1到n,按顺序往地上铺。后面的地毯会压在先前的地毯上面,所以当查询某个点时,问题答案应该是“覆盖这个点的所有地毯里,编号最大(也就是最在上面)的那一张”。
每张地毯用四个整数描述:a b g k,表示地毯左下角坐标是 (a, b),在x轴方向长度为g,在y轴方向长度为k。换句话说,这张地毯覆盖的矩形区域是:
code复制a <= x <= a + g
b <= y <= b + k
注意这里的边界是闭区间,也就是说地毯四条边的位置也算被覆盖。这是很多同学写错的第一处细节,后面我会专门说。
最后题目给出一个查询点 (x, y),要求输出覆盖这个点的最上层地毯编号;如果没有任何一张地毯覆盖这个点,输出 -1。
1.2 先别急着写代码,看一眼数据范围
很多同学一看到“铺地毯”三个字,第一反应是:开一个二维数组模拟地面,每来一张地毯就把对应区域涂成当前编号,最后直接输出 g[x][y]。
这个思路在平面很小的时候能过,但在竞赛题里几乎必死。原因是二维数组的规模取决于坐标系的范围,而不是地毯的数量。
假设坐标系范围到了 100000 × 100000,你要开的 bool 数组就是:
code复制100000 * 100000 = 1e10 个元素
C++ 里 bool 类型实际占1字节,也就是说光是数组就要约 10GB 内存。即使你把 bool 用位运算压缩到一个bit,也需要约 1.25GB,大多数OJ的内存限制只有 128MB 或者 256MB,内存直接爆掉。
就算你狠下心用离散化压缩坐标,模拟每一张地毯的矩形填充也是一个隐藏炸弹。每张地毯如果覆盖了很大的面积,填充一次就要循环很多次,n张地毯叠起来,时间开销完全不可控。
所以这道题真正考察的第一个点就是:你得意识到二维模拟是死路,真正的信息根本不需要铺满整个平面。
1.3 “从前往后查”和“从后往前查”的差别在哪里
既然不能开平面数组,另一个朴素想法是:把每张地毯的参数存下来,然后从头到尾遍历一遍,判断查询点是否在每张地毯内部。
这个思路其实已经接近正解了,只是遍历方向还有讲究。如果从1号地毯查到n号地毯,你会发现有可能多张地毯都覆盖了这个点,但最终答案要的是编号最大的那张,所以你得把所有覆盖到的编号都记下来,取最大值。这样做没问题,但多了一个变量,逻辑上也绕了一下。
更自然的做法是反过来:从n号地毯往
