题目描述见链接 .
将 矩形的 长 作为 , 矩形的 宽 作为 , 放到 平面直角坐标系 中,
题目转化 为使用 最小的矩阵面积和 覆盖所有点,
可以发现当矩形 满足 且 时, 矩形 是可以忽略的,
于是将所有 类矩形代表的坐标从坐标系中抹除, 可以发现剩下的矩形坐标组成了一个 单调递减 的折线,
然后再使用 最小的矩阵面积和 覆盖所有点,
这个时候可以发现 覆盖时 按 横坐标 从左到右分成连续的几段进行覆盖是最优的,
由此可以想到设 表示覆盖前 个点所使用的最小矩形面积和,
状态转移, , 根据单调性, .
直接转移 时间复杂度 , 考虑优化, 将方程化简为 ,
可以发现是 斜率优化 的形式, .
目标是使得 最小, 且 斜率 为 负数 且 单调递减, 所以使用 单调队列 维护 下凸包 即可 .
- 十年 一场空, 不开 见祖宗 .
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
const int maxn = 50005;
int N;
int Tmp_1;
int que[maxn];
ll F[maxn];
bool vis[maxn];
struct Node{ int h, w; } A[maxn];
bool cmp(Node a, Node b){ return a.w==b.w?a.h<b.h:a.w<b.w; }
double slope(int a, int b){ return (1.0*F[a] - F[b])/(1.0*A[a+1].h - A[b+1].h); }
int main(){
scanf("%d", &N);
for(reg int i = 1; i <= N; i ++) scanf("%d%d", &A[i].w, &A[i].h);
std::sort(A+1, A+N+1, cmp); int max_h = 0;
for(reg int i = N; i >= 1; i --){ if(A[i].h <= max_h) vis[i] = 1; max_h = std::max(max_h, A[i].h); }
for(reg int i = 1; i <= N; i ++) if(!vis[i]) A[++ Tmp_1] = A[i];
N = Tmp_1; int tl = 0, hd = 1; que[++ tl] = 0;
for(reg int i = 1; i <= N; i ++){
double cur_k = -1.0*A[i].w;
while(tl-hd+1 >= 2 && slope(que[hd], que[hd+1]) > cur_k) hd ++;
F[i] = F[que[hd]] + 1ll*A[que[hd]+1].h*A[i].w;
while(tl-hd+1 >= 2 && slope(que[tl-1], i) > slope(que[tl], que[tl-1])) tl --;
que[++ tl] = i;
}
printf("%lld
", F[N]);
return 0;
}