题解 - 矩形覆盖
题目大意
给定一个由 \(N\) 个平行矩形组成的不规则图形;
你每次可以放置一个长宽任意的矩形(它不能与你已经放置的矩形重叠,也不能跨越过不规则图形的边界);
最少需要几个矩形才能完全覆盖该图形?
思路简析
将题目中给定的矩形称为给定矩形;
将自己放置的矩形称为自定义矩形;
将自定义矩形完全覆盖给定矩形称为完全消除。
由于总共有 \(N\) 个给定矩形,并且我们所能放置的也是矩形,因此在最坏的情况下,也只需要放置 \(N\) 个自定义矩形(每个给定矩形放置一个)。
考虑一下,当你不能完全覆盖给定矩形时,你就不能减少所需的自定义矩形,因为最初它也只需要一个自定义矩形,而当你没有完全覆盖它时,你最终必须在它上面添加最后一个自定义矩形。
因此,只有当一个自定义矩形能够同时消除两个或以上的给定矩形时,减少自定义矩形的需求才能真正被达到。
因为所有给定矩形的底边在同一条直线上,所以真正需要考虑的只有它们的顶边,而要同时完全消除 \(x\) 个给定矩形,它们的顶边高度必须相同,且中间不存在更低的给定矩形。
总之,我们要寻找的是有多少组具有相同高度、且没有被中间较低的给定矩形分隔开的给定矩形。
代码实现
由于这个解法是通过及时排除不可能的选项解决的问题,因此使用单调栈。
遍历解决,且由于每一次处理不依赖以后的数据,所以可以边输入边处理:
- 如果当前的给定矩形高度大于栈顶的给定矩形高度,则目前无法执行任何操作,直接入栈;
- 如果当前给定矩形高度等于栈顶的给定矩形高度,那么这两个给定矩形可以使用同一个自定义矩形。
理论上,应该将原来的给定矩形出栈,将当前给定矩形入栈。但是,由于原来给定矩形高度等于当前给定矩形高度,因此在代码中反映为无操作。 - 如果当前的给定矩形高度小于栈顶的给定矩形高度,考虑到当前有一个较低的给定矩形将其与所有后续的给定矩形分隔开,则它不能被任何后续自定义矩形完全消除。因此,所有这样的给定矩形都应该被从栈中弹出,再进一步处理。
此时,栈顶的给定矩形高度一定小于等于当前给定矩形高度。
所以可以按照前两种情况处理。
CODE
Time complexity:\(O(n)\)。
#include <bits/stdc++.h>
namespace {
#define fiin(x) freopen(x".in", "r", stdin)
#define fiout(x) freopen(x".out", "w", stdout)
#define files(x) fiin(x), fiout(x)
using namespace std;
#define ll long long
#define db double
const int man = 2.5e5;
}
int n, tp, res;
int stk[man];
int main () {
#ifndef ONLINE_JUDGE
files("test");
#endif
scanf("%d", &n); res = n;
for (int p, h, i = 1; i <= n; ++ i) {
scanf("%d%d", &p, &h);
if (h < stk[tp]) while (h < stk[--tp]) ;
if (h > stk[tp]) stk[++tp] = h;
else if (h == stk[tp]) -- res;
} printf("%d", res);
return 0;
}