题解
dp求解,考虑某个矩形长宽都被另一个完全包含则这个矩形可以不计算代价。将矩形按x降y升排列。
转移方程 f[i] = min(f[i], f[j] + x[j + 1] * y[i]) 表示最大x*最大y,复杂度O(N^2),斜率优化。
f[i]通过j转移比k转移更优(k < j < i)斜率方程
(f[j] - f[k]) / (x[k + 1] - x[j + 1]) < y[i]
当前i点从j转移比k优则从t点从j转移比k优(j < i < t) 因为随着i的增大y也会增大 不等式恒成立
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 5e4 + 10;
ll f[N]; //f[i]前i项的最小代价
int ls[N], head, tail;
/*
转移方程f[i] = min(f[i], f[j] + x[j + 1] * y[i]) 最大x*最大y
f[i]通过j转移比k转移更优(k < j < i)斜率方程
(f[j] - f[k]) / (x[k + 1] - x[j + 1]) < y[i]
*/
struct node
{
ll x, y;
bool operator < (const node &oth) const //按x降y升排列
{
if (x != oth.x)
return x > oth.x;
return y > oth.y;
}
}a[N];
inline ll up(int k, int j)
{
//ll res = f[j] - f[k];
return f[j] - f[k];
}
inline ll down(int k, int j)
{
//ll res = a[k + 1].x - a[j + 1].x;
return a[k + 1].x - a[j + 1].x;
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int n, m = 0;
cin >> n;
for (int i = 1; i <= n; ++i)
scanf("%d%d", &a[i].x, &a[i].y);
sort(a + 1, a + n + 1);
int mx = 0; //最大的y
for (int i = 1; i <= n; ++i) //消去xy完全被另一个包含的项
if (a[i].y > mx)
a[++m] = a[i], mx = a[i].y;
ls[tail++] = 0; //可以通过0转移
for (int i = 1; i <= m; ++i)
{
//i后移则只会导致y增大 不等式恒成立
while (head + 1 < tail && up(ls[head], ls[head + 1]) <= a[i].y * down(ls[head], ls[head + 1]))
head++; //淘汰表头
int j = ls[head];
f[i] = f[j] + (a[j + 1].x * a[i].y);
while (head + 1 < tail && up(ls[tail - 2], ls[tail - 1]) * down(ls[tail - 1], i) >= up(ls[tail - 1], i) * down(ls[tail - 2], ls[tail - 1]))
tail--; //淘汰表尾
ls[tail++] = i; //插入
}
printf("%lld\n", f[m]);
return 0;
}