前言
(MD) 做线性基做到自闭。。。智商真的太低了。
Solution
考虑到是沿原点对称,我们可以直接算第一象限的部分再乘 (4) 就行了。
直接 (DP) 是不行的,因为有 (i,j) 满足 (x[i]<=x[j]&&y[i]<=y[j])。这时的 (i) 是不方便计算的,因为可能或者说是一定用可覆盖 (j) 的矩形来覆盖 (i)。换句话说,这里的 (i) 对答案是不会造成影响的。
我们将这样的点删掉,再将 (x) 从小到大排序。这会构成一个单调递减的函数。
我们设 (dp[i][0]) 为填补前面的某个矩形使其包含点 (i),(dp[i][1]) 为直接构造一个矩形来包含点 (i)。
你可能会想到一种情况:对于 (x[i]<x[j]<x[k]),(i) 直接建造矩形,(j) 在 (i) 的基础上添加面积,这时 (k) 在 (j) 的与 (i) 的基础上添加面积,是否可能会计算重复的部分。
其实不会,因为 (j) 在 (i) 的基础上添加面积记录在 (dp[j][0]),而 (k) 接触的部分只会涉及到 (dp[i][1])。
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
", min(dp[1][0], dp[1][1]) << 2);
return 0;
}