\(\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;
}