\(\bf{Description}\)

给定二维平面上 \(n\) 个点,求多个以原点为中心的矩形,将所有的点包括的矩形面积和最小值。

\(|x_i|,|y_i|\le 5\cdot 10^7,n\le 5000\)

\(\bf Solution\)

由于沿原点对称,我们可以将所有点都扔到第一象限,最后将答案乘以 \(4\)

套路的做法是将所有满足 \(\exist j,x_i\le x_j \and y_i\le y_j\)\(i\) 全都删掉,它们对答案都没有影响。再将点按横坐标排序,它们的纵坐标是递减的。

于是可以设计 \(dp_{i,0/1}\) 表示为新建一个矩形包含 \(i\) 与从原来的矩形扩展一些长度来包含 \(i\)(因为纵坐标递减所以一定可行)。转移是 \(\mathcal O(n^2)\) 的。

\(\bf Code\)

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N = 5005;

int n, cnt, maxx;
ll dp[N][2];
struct node {ll x, y;} s[N], t[N];

int read() {
    int x = 0, f = 1; char s;
    while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
    while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
    return x * f;
}

bool cmp(const node a, const node b) {return a.x < b.x;}

int main() {
    n = read();
    for(int i = 1; i <= n; ++ i) s[i].x = abs(read()), s[i].y = abs(read());
    sort(s + 1, s + n + 1, cmp); ++ cnt;
    maxx = t[cnt].y = s[n].y, t[cnt].x = s[n].x;
    for(int i = n - 1; i; -- i)
        if(s[i].y > maxx)  {
            maxx = s[i].y;
            t[++ cnt] = s[i];
        }
    for(int i = cnt; i; -- i) {
        dp[i][1] = min(dp[i + 1][0], dp[i + 1][1]) + t[i].x * t[i].y;
        dp[i][0] = dp[i][1];
        for(int j = i + 1; j <= cnt; ++ j) dp[i][0] = min(dp[i][0], dp[j][1] + t[j].y * (t[i].x - t[j].x));
    }
    printf("%lld\n", min(dp[1][0], dp[1][1]) << 2);
    return 0;
}
posted on 2020-05-12 20:39  Oxide  阅读(107)  评论(0编辑  收藏  举报