利用后铺地毯在上面的性质,从编号大的地毯往前枚举,第一个覆盖查询点的就是答案。
OJ: luogu
题目 ID: P1003
难度:入门
标签:模拟枚举
日期: 2026-06-19 00:21
题意
有 n 张矩形地毯按编号从小到大依次铺在平面上。
给定一个查询点 (x,y),要求输出覆盖这个点的最上面那张地毯编号;如果没有地毯覆盖它,输出 -1。
思路
先看一个可以直接验证想法的朴素解:
按铺设顺序从前往后扫一遍,凡是覆盖查询点的地毯都把答案更新成当前编号。
cpp
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
int n;
int a[MAXN], b[MAXN], g[MAXN], k[MAXN];
int x, y;
void solve() {
int ans = -1;
// 按铺设顺序检查,后面覆盖到前面时直接更新答案。
for (int i = 1; i <= n; i++) {
if (a[i] <= x && x <= a[i] + g[i] &&
b[i] <= y && y <= b[i] + k[i]) {
ans = i;
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i] >> b[i] >> g[i] >> k[i];
}
cin >> x >> y;
solve();
return 0;
}这个做法已经能做出来,但还有一个更贴合题意的观察:
后铺的地毯一定在前铺的地毯上面。
所以如果一个点被多张地毯覆盖,真正的答案一定是编号最大的那一张。
于是我们完全可以反过来做:
- 从第
n张地毯开始往前找 - 第一张覆盖查询点的地毯,就是最上面的地毯
这样一旦找到就可以立刻结束。
判断一张地毯是否覆盖查询点时,要注意边界和顶点也算覆盖,所以比较要写成闭区间判断。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
int n;
int a[MAXN], b[MAXN], g[MAXN], k[MAXN];
int x, y;
int cover(int id, int px, int py) {
return a[id] <= px && px <= a[id] + g[id] &&
b[id] <= py && py <= b[id] + k[id];
}
void solve() {
for (int i = n; i >= 1; i--) {
if (cover(i, x, y)) {
cout << i << '\n';
return;
}
}
cout << -1 << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i] >> b[i] >> g[i] >> k[i];
}
cin >> x >> y;
solve();
return 0;
}复杂度
时间复杂度是
总结
这题的关键不在矩形本身,而在铺设顺序。
抓住“后铺的在上面”这句话,直接逆序枚举,就能把答案很快找出来。
