1 条题解

  • 0
    @ 2026-5-16 14:10:45

    题目解析

    本题的核心是:给定平面上 nn 个点(怪物),你可以至多移动一个点到任意空位置,然后选择一个轴对齐矩形覆盖所有点,矩形内每个格子花费 11 硬币,问最小花费。

    关键观察

    1. 不移动情况下的最小矩形

    如果不移动任何点,覆盖所有点的最小矩形由坐标的极值决定:

    • 宽度:max(xi)min(xi)+1\max(x_i) - \min(x_i) + 1
    • 高度:max(yi)min(yi)+1\max(y_i) - \min(y_i) + 1

    面积为:

    $$\text{ans} = (\max x - \min x + 1) \times (\max y - \min y + 1) $$

    2. 移动一个点的作用

    移动一个点的目的是减少矩形的一维宽度。例如:

    • 如果一个点是 xx 坐标的最大值点,移除它后新的 maxx\max x 变成第二大的 xx
    • 类似地,如果一个点是 xx 坐标的最小值点,移除它后新的 minx\min x 变成第二小的 xx

    因此,移动某个点可以消除它在某个轴向上作为极值的影响

    3. 移动后能否放入原矩形?

    对于除了被移动点 pp 之外的 n1n-1 个点,它们的最小矩形面积是:

    S=(宽度)×(高度)S = (\text{宽度}) \times (\text{高度})

    其中宽度和高度由剩余的 n1n-1 个点的极值决定。

    如果 S=n1S = n-1,意味着这个矩形正好被这 n1n-1 个点填满(没有空位)。此时,如果我们想把这个点移动到这个矩形内部,就必须扩大矩形的一边,因为矩形内没有空位了。

    如果 S>n1S > n-1,说明矩形内有空位,我们可以直接把点移动到任意空位上,不需要扩大矩形。


    算法步骤

    1. 预处理所有极值

    我们需要快速知道:去掉某个点后,新的极值是多少

    这可以通过维护每维的最大值和次大值、最小值和次小值来实现:

    • mx1:当前最大 xx 坐标
    • mx2:当前第二大 xx 坐标
    • mn1:当前最小 xx 坐标
    • mn2:当前第二小 xx 坐标

    对于 yy 坐标同理。

    2. 数据结构设计

    代码中定义了 min_max 结构体,用于维护某一维的统计信息:

    • 构造函数:用前两个点初始化 mx1, mx2, mn1, mn2
    • add(x):加入一个新点,更新四个值
    • get_seg(x):返回忽略值为 xx 的点后的区间长度(即 maxmin+1\max - \min + 1

    get_seg(x) 的实现逻辑:

    int get_seg(int x){
        pair<int, int> res = {mn1, mx1};  // 当前最小和最大
        if(x == mn1) res.x = mn2;         // 如果忽略的是最小值,用次小值代替
        if(x == mx1) res.y = mx2;         // 如果忽略的是最大值,用次大值代替
        return res.y - res.x + 1;         // 返回区间长度
    }
    

    3. 整体算法流程

    步骤 1:预处理所有点的 xxyy 的极值信息

    min_max xc(coord[0].x, coord[1].x), yc(coord[0].y, coord[1].y);
    for(int i = 2; i < n; ++i){
        xc.add(coord[i].x);
        yc.add(coord[i].y);
    }
    

    步骤 2:计算不移动任何点时的答案

    int ans = xc.get_seg(-1) * yc.get_seg(-1);  // -1 表示不忽略任何点
    

    步骤 3:尝试移动每个点

    对于第 ii 个点,计算忽略它后的矩形宽度和高度:

    int x = xc.get_seg(coord[i].x);
    int y = yc.get_seg(coord[i].y);
    
    • 如果 x×y=n1x \times y = n-1,说明矩形被剩余点填满,需要扩大一边:$$\text{新面积} = \min((x+1) \times y,\ x \times (y+1)) $$
    • 否则,可以直接放入矩形内:新面积=x×y\text{新面积} = x \times y

    更新答案:

    ans = min(ans, 新面积);
    

    步骤 4:输出答案


    样例验证

    样例 1:n=3n=3,点 (1,1),(1,2),(2,1)(1,1),(1,2),(2,1)

    不移动时:x:[1,2]x: [1,2],宽度 =2=2y:[1,2]y: [1,2],高度 =2=2;面积 =4=4

    尝试移动 (1,1)(1,1)

    • 剩余点:(1,2),(2,1)(1,2),(2,1)
    • x:[1,2]x: [1,2],宽度 =2=2y:[1,2]y: [1,2],高度 =2=2S=4>n1=2S=4 > n-1=2
    • 可直接放入:面积 =4=4

    移动 (1,2)(1,2)(2,1)(2,1) 同理。

    但最优解是什么?实际答案样例输出是 33。这是因为题目中你可以在移动点之前选择一个新的位置,然后选择矩形覆盖所有点。移动后总点数还是 nn,但矩形可以更小。

    重新理解:移动一个点后,所有 nn 个点(包括移动后的)都被矩形覆盖。所以实际计算的是:移动后的 nn 个点的最小矩形面积。

    修正理解

    算法中 x * y忽略该点后剩余 n1n-1 个点的矩形面积。但我们要覆盖 nn 个点,所以:

    • 如果能放进矩形内,矩形大小不变:面积 =x×y= x \times y
    • 如果不能放进(填满了),需要扩大一边:面积 =min((x+1)y,x(y+1))= \min((x+1)y, x(y+1))

    所以面积公式正确。


    复杂度分析

    • 时间复杂度:O(n)O(n),每个点只处理一次
    • 空间复杂度:O(n)O(n),存储所有点坐标

    由于所有测试用例的 nn 之和不超过 2×1052 \times 10^5,完全可行。


    总结

    本题的核心技巧:

    1. 极值维护:用最大值/次大值、最小值/次小值快速处理"去掉一个点"后的极值变化
    2. 分类讨论
      • 矩形有空位 → 直接放入
      • 矩形被填满 → 扩大一边
    3. 贪心枚举:尝试移动每个点,取最小值

    这样可以在 O(n)O(n) 时间内解决每个测试用例。

    • 1

    信息

    ID
    7094
    时间
    1000ms
    内存
    256MiB
    难度
    3
    标签
    递交数
    1
    已通过
    1
    上传者