AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

Codeforces 2114D. Come a Little Closer    原题链接    中等

作者: 作者的头像   pein531 ,  2025-06-10 10:45:41 · 北京 ,  所有人可见 ,  阅读 2


0


题目描述

难度分:$1400$

输入$T(\leq 10^4)$表示$T$组数据。所有数据的$n$之和$\leq 2 \times 10^5$。

每组数据输入$n(1 \leq n \leq 2 \times 10^5)$和$n$个点$(x_i,y_i)$,范围$[1,10^9]$。保证$n$个点互不相同。

有一个$10^9 \times 10^9$的矩阵,矩阵中有$n$个怪物,第$i$个怪物在$(x_i,y_i)$单元格中。

你最多可以把一个怪物移动到另一个没有怪物的单元格中。输出包含所有怪物的最小子矩形的面积(即子矩形中的单元格个数)。

输入样例

7
3
1 1
1 2
2 1
5
1 1
2 6
6 4
3 3
8 2
4
1 1
1 1000000000
1000000000 1
1000000000 1000000000
1
1 1
5
1 2
4 2
4 3
3 1
3 2
3
1 1
2 5
2 2
4
4 3
3 1
4 4
1 2

输出样例

3
32
1000000000000000000
1
6
4
8

算法

枚举+贪心

比较容易发现贪心策略,用有序表$xcnt$和$ycnt$构建两个映射,分别表示指定横坐标对应的点数、指定纵坐标对应的点数。分为以下两种情况:

  1. 如果给定的$n$个点已经紧密堆积成一个矩形了(面积为$n$),说明$n$个点之间严丝合缝,已经是最优解了,答案就是$n$。
  2. 否则将最外侧的一个点移动到中间的空位,假设$n$个点中横纵左边的最小值和最大值分别为$xmin$、$xmax$、$ymin$、$ymax$。这里面又有$4$种情况:如果$xmin$对应的点只有一个,就可以把它往内部移动,假设这个点是$(x,y)$(其中$x=xmin$),将这个点从$xcnt$和$ycnt$中删除,就可以得到剩下$n-1$个点的$xmin$、$xmax$、$ymin$、$ymax$,只要$(xmax-xmin+1) \times (ymax-ymin+1) \gt n-1$,说明剩下的$n-1$个点中间有空位,把$(x,y)$移进去就可以了,答案为$(xmax-xmin+1) \times (ymax-ymin+1)$。否则$(x,y)$就只能贴在最外层,答案是$(xmax-xmin+1) \times (ymax-ymin+2)$和$(xmax-xmin+2) \times (ymax-ymin+1)$的较小值。同理分析$xmax$只有一个,$ymax$、$ymin$只有一个的情况,它们对应答案的最小值就是最终答案。

复杂度分析

时间复杂度

遍历$O(n)$个点预处理出$xcnt$和$ycnt$两个有序表,时间复杂度为$O(nlog_2n)$。为了快速从$xmin$、$xmax$、$ymin$、$ymax$定位出点对应的纵坐标或横坐标,还需要$x2y$、$y2x$两个哈希表。之后分情况讨论只需要对有序表$xcnt$和$ycnt$操作,时间复杂度为$O(log_2n)$。因此,整个算法的时间复杂度为$O(nlog_2n)$。

空间复杂度

空间消耗主要在于两个有序表$xcnt$和$ycnt$,两个哈希表$x2y$和$y2x$,它们之中都有$O(n)$级别的键值对数量。因此,整个算法的额外空间复杂度为$O(n)$。

C++ 代码

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;

struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        map<int, int> xcnt, ycnt;
        unordered_map<int, int, custom_hash> x2y, y2x;
        int xmax = -1e9, xmin = 1e9, ymax = -1e9, ymin = 1e9;
        for(int i = 0; i < n; i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            xcnt[x]++;
            ycnt[y]++;
            x2y[x] = y;
            y2x[y] = x;
            xmax = max(xmax, x);
            xmin = min(xmin, x);
            ymax = max(ymax, y);
            ymin = min(ymin, y);
        }
        LL lx = xmax - xmin + 1, ly = ymax - ymin + 1;
        if(ly * lx == n) {
            printf("%d\n", n);
        }else {
            LL ans = lx * ly;
            if(xcnt.begin()->second == 1 || xcnt.rbegin()->second == 1) {
                if(xcnt.begin()->second == 1) {
                    int x = xcnt.begin()->first, y = x2y[x];
                    xcnt[x]--, ycnt[y]--;
                    if(xcnt[x] == 0) xcnt.erase(x);
                    if(ycnt[y] == 0) ycnt.erase(y);
                    xmin = xcnt.begin()->first, xmax = xcnt.rbegin()->first;
                    ymin = ycnt.begin()->first, ymax = ycnt.rbegin()->first;
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) > n - 1) {
                        ans = min(ans, (xmax - xmin + 1LL) * (ymax - ymin + 1));
                    }
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) == n - 1) {
                        ans = min(ans, min((xmax - xmin + 2LL) * (ymax - ymin + 1), (xmax - xmin + 1LL) * (ymax - ymin + 2)));
                    }
                    xcnt[x]++, ycnt[y]++;
                }
                if(xcnt.rbegin()->second == 1) {
                    int x = xcnt.rbegin()->first, y = x2y[x];
                    xcnt[x]--, ycnt[y]--;
                    if(xcnt[x] == 0) xcnt.erase(x);
                    if(ycnt[y] == 0) ycnt.erase(y);
                    xmin = xcnt.begin()->first, xmax = xcnt.rbegin()->first;
                    ymin = ycnt.begin()->first, ymax = ycnt.rbegin()->first;
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) > n - 1) {
                        ans = min(ans, (xmax - xmin + 1LL) * (ymax - ymin + 1));
                    }
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) == n - 1) {
                        ans = min(ans, min((xmax - xmin + 2LL) * (ymax - ymin + 1), (xmax - xmin + 1LL) * (ymax - ymin + 2)));
                    }
                    xcnt[x]++, ycnt[y]++;
                }
            }
            if(ycnt.begin()->second == 1 || ycnt.rbegin()->second == 1) {
                if(ycnt.begin()->second == 1) {
                    int y = ycnt.begin()->first, x = y2x[y];
                    xcnt[x]--, ycnt[y]--;
                    if(xcnt[x] == 0) xcnt.erase(x);
                    if(ycnt[y] == 0) ycnt.erase(y);
                    xmin = xcnt.begin()->first, xmax = xcnt.rbegin()->first;
                    ymin = ycnt.begin()->first, ymax = ycnt.rbegin()->first;
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) > n - 1) {
                        ans = min(ans, (xmax - xmin + 1LL) * (ymax - ymin + 1));
                    }
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) == n - 1) {
                        ans = min(ans, min((xmax - xmin + 2LL) * (ymax - ymin + 1), (xmax - xmin + 1LL) * (ymax - ymin + 2)));
                    }
                    xcnt[x]++, ycnt[y]++;
                }
                if(ycnt.rbegin()->second == 1) {
                    int y = ycnt.rbegin()->first, x = y2x[y];
                    xcnt[x]--, ycnt[y]--;
                    if(xcnt[x] == 0) xcnt.erase(x);
                    if(ycnt[y] == 0) ycnt.erase(y);
                    xmin = xcnt.begin()->first, xmax = xcnt.rbegin()->first;
                    ymin = ycnt.begin()->first, ymax = ycnt.rbegin()->first;
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) > n - 1) {
                        ans = min(ans, (xmax - xmin + 1LL) * (ymax - ymin + 1));
                    }
                    if((xmax - xmin + 1LL) * (ymax - ymin + 1) == n - 1) {
                        ans = min(ans, min((xmax - xmin + 2LL) * (ymax - ymin + 1), (xmax - xmin + 1LL) * (ymax - ymin + 2)));
                    }
                    xcnt[x]++, ycnt[y]++;
                }
            }
            printf("%lld\n", ans);
        }
    }
    return 0;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息