分析
首先把宽度
l
l
l按第一关键字从小到大排序,高度
h
h
h按第二关键字从大到小排序,用一个栈把存在
h
[
x
]
≤
h
[
y
]
,
l
[
x
]
≤
l
[
y
]
h[x]\leq h[y],l[x]\leq l[y]
h[x]≤h[y],l[x]≤l[y]的情况消掉,然后一个显然的性质可以发现最优情况肯定是选择连续的一段,那么可以这样列出dp方程
d
p
[
i
]
=
min
{
d
p
[
j
]
+
h
[
j
+
1
]
∗
l
[
i
]
}
dp[i]=\min\{dp[j]+h[j+1]*l[i]\}
dp[i]=min{dp[j]+h[j+1]∗l[i]}
设
k
(
j
<
k
)
k(j<k)
k(j<k)优于
j
j
j,那么
d
p
[
j
]
+
h
[
j
+
1
]
∗
l
[
i
]
≥
d
p
[
k
]
+
h
[
k
+
1
]
∗
l
[
i
]
dp[j]+h[j+1]*l[i]\geq dp[k]+h[k+1]*l[i]
dp[j]+h[j+1]∗l[i]≥dp[k]+h[k+1]∗l[i]
那么化简可得
d
p
[
j
]
−
d
p
[
k
]
≥
(
h
[
k
+
1
]
−
h
[
j
+
1
]
)
∗
l
[
i
]
dp[j]-dp[k]\geq (h[k+1]-h[j+1])*l[i]
dp[j]−dp[k]≥(h[k+1]−h[j+1])∗l[i]
因为若
h
[
k
+
1
]
≥
h
[
j
+
1
]
h[k+1]\geq h[j+1]
h[k+1]≥h[j+1],那么
l
[
k
+
1
]
>
l
[
j
+
1
]
l[k+1]>l[j+1]
l[k+1]>l[j+1]也不符合消掉的情况,所以
h
[
k
+
1
]
<
h
[
j
+
1
]
h[k+1]<h[j+1]
h[k+1]<h[j+1]
d
p
[
j
]
−
d
p
[
k
]
h
[
k
+
1
]
−
h
[
j
+
1
]
≤
l
[
i
]
\frac{dp[j]-dp[k]}{h[k+1]-h[j+1]}\leq l[i]
h[k+1]−h[j+1]dp[j]−dp[k]≤l[i]
显然
l
l
l是单调递增的,所以维护下凸壳,单调队列优化,时间复杂度
O
(
n
)
O(n)
O(n)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
struct rec{
int x,y;
bool operator <(const rec &t)const{
return x<t.x||(x==t.x&&y>t.y);
}
}a[50001];
long long dp[50001]; int n,top,head,tail,q[50001];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline double slope(int j,int k){return 1.0*(dp[k]-dp[j])/(a[j+1].y-a[k+1].y);}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) a[i]=(rec){iut(),iut()};
sort(a+1,a+1+n);
for (rr int i=1;i<=n;++i){
while (top&&a[top].y<=a[i].y) --top;
a[++top]=a[i];
}
n=top,head=1,tail=0,q[++tail]=0;
for (rr int i=1;i<=n;++i){
while (head<tail&&slope(q[head],q[head+1])<=a[i].x) ++head;
dp[i]=dp[q[head]]+1ll*a[i].x*a[q[head]+1].y;
while (head<tail&&slope(q[tail-1],q[tail])>=slope(q[tail],i)) --tail;
q[++tail]=i;
}
return !printf("%lld",dp[n]);
}