土 地 购 买 土地购买 土地购买
题目描述见链接 .
正 解 部 分 \color{red}{正解部分} 正解部分
将 矩形的 长 作为
x
x
x, 矩形的 宽 作为
y
y
y, 放到 平面直角坐标系 中,
题目转化 为使用 最小的矩阵面积和 覆盖所有点,
可以发现当矩形
a
,
b
a, b
a,b 满足
a
.
x
≤
b
.
x
a.x \le b.x
a.x≤b.x 且
a
.
y
≤
b
.
y
a.y \le b.y
a.y≤b.y 时, 矩形
a
a
a 是可以忽略的,
于是将所有
a
a
a 类矩形代表的坐标从坐标系中抹除, 可以发现剩下的矩形坐标组成了一个 单调递减 的折线,
然后再使用 最小的矩阵面积和 覆盖所有点,
这个时候可以发现 覆盖时 按 横坐标 从左到右分成连续的几段进行覆盖是最优的,
由此可以想到设
F
[
i
]
F[i]
F[i] 表示覆盖前
i
i
i 个点所使用的最小矩形面积和,
状态转移,
F
[
i
]
=
min
(
F
[
k
]
+
c
o
s
t
[
k
+
1
,
i
]
)
F[i] = \min(F[k] + cost[k+1, i])
F[i]=min(F[k]+cost[k+1,i]), 根据单调性,
c
o
s
t
[
k
+
1
,
i
]
=
h
k
+
1
×
w
i
cost[k+1, i] = h_{k+1} \times w_i
cost[k+1,i]=hk+1×wi .
直接转移 时间复杂度
O
(
N
2
)
O(N^2)
O(N2), 考虑优化, 将方程化简为
F
[
k
]
=
−
w
i
×
h
k
+
1
+
F
[
i
]
F[k] = -w_i \times h_{k+1} + F[i]
F[k]=−wi×hk+1+F[i],
可以发现是 斜率优化 的形式,
y
=
F
[
k
]
,
k
=
−
w
i
,
x
=
h
k
+
1
,
b
=
F
[
i
]
y = F[k], k = -w_i, x = h_{k+1}, b = F[i]
y=F[k],k=−wi,x=hk+1,b=F[i] .
目标是使得 F [ i ] F[i] F[i] 最小, 且 斜率 为 负数 且 单调递减, 所以使用 单调队列 维护 下凸包 即可 .
实 现 部 分 \color{red}{实现部分} 实现部分
- 十年 O I OI OI 一场空, 不开 l o n g l o n g long\ long long long 见祖宗 .
#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\n", F[N]);
return 0;
}