题面描述
思路
瞎扯
乍一看,貌似找不到什么有序的东西。
先排序吧(第一关键字为 x x x坐标,第二关键字为 y y y坐标,都以从小到大排序)。
类似下图
发现相邻的两块土地(排序后)
i
,
i
+
1
i,i+1
i,i+1,如果
y
i
<
y
i
+
1
y_i<y_{i+1}
yi<yi+1,那么买第
i
+
1
i+1
i+1块土地,顺便可以带上第
i
i
i块土地(岂不美哉!,买一送一啊!),
按照这样的思想,我们可以买一送
n
n
n啊。
之后去掉送的土地,保留有用的(至于如何有用,详见上文)土地。
如下图
之后我们就可以愉快地推状态转移方程啦!
设离散化之后的数组为 b b b(保证 x x x坐标不下降)
F i = min ( F j + y b j + 1 ∗ x b i ) F_i=\min(F_j+y_{b_{j+1}}*x_{b_i}) Fi=min(Fj+ybj+1∗xbi)
y b j + 1 y_{b_{j+1}} ybj+1保证是 b [ j + 1 , i ] b_{[j+1,i]} b[j+1,i]后最大的纵坐标哦,因为后面如果有比它大的纵坐标, b j + 1 b_{j+1} bj+1根本不存在于数组中。
证明决策单调性
设有
F
k
+
y
b
k
+
1
∗
x
b
i
≤
F
j
+
y
b
j
+
1
∗
x
b
i
(
j
<
k
<
i
)
F_k+y_{b_{k+1}}*x_{b_i}\le F_j+y_{b_{j+1}}*x_{b_i} (j<k<i)
Fk+ybk+1∗xbi≤Fj+ybj+1∗xbi(j<k<i)
证明:对于未来状态 t t t,都有
F k + y b k + 1 ∗ x b t ≤ F j + y b j + 1 ∗ x b t ( j < k < i < t ) F_k+y_{b_{k+1}}*x_{b_t}\le F_j+y_{b_{j+1}}*x_{b_t}(j<k<i<t) Fk+ybk+1∗xbt≤Fj+ybj+1∗xbt(j<k<i<t)
由于 x b t , y b k + 1 , y b j + 1 x_{b_t},y_{b_{k+1}},y_{b_{j+1}} xbt,ybk+1,ybj+1不变,证毕。
这怕不是不用证明
踢队头
F k + y b k + 1 ∗ x b i ≤ F j + y b j + 1 ∗ x b i ( j < k < i ) F_k+y_{b_{k+1}}*x_{b_i}\le F_j+y_{b_{j+1}}*x_{b_i} (j<k<i) Fk+ybk+1∗xbi≤Fj+ybj+1∗xbi(j<k<i)
F j − F k ≥ y b k + 1 ∗ x b i − y b j + 1 ∗ x b i F_j-F_k\ge y_{b_{k+1}}*x_{b_i}-y_{b_{j+1}}*x_{b_i} Fj−Fk≥ybk+1∗xbi−ybj+1∗xbi
由 y b k + 1 ≤ y b j + 1 y_{b_{k+1}}\le y_{b_{j+1}} ybk+1≤ybj+1可知,
F j − F k y b k + 1 − y b j + 1 ≤ x b i \frac{F_j-F_k}{y_{b_{k+1}}-y_{b_{j+1}}}\le x_{b_i} ybk+1−ybj+1Fj−Fk≤xbi
因此,当上述不等式成立时, k k k优于 j j j。
如果 c a l c ( q h e a d , q t a i l ) = F h e a d − F h e a d + 1 y b h e a d + 1 − y b h e a d ≤ x b i calc(q_{head},q_{tail})=\frac{F_{head}-F_{head+1}}{y_{b_{head+1}}-y_{b_{head}}}\le x_{b_{i}} calc(qhead,qtail)=ybhead+1−ybheadFhead−Fhead+1≤xbi
说明 h e a d + 1 head+1 head+1优于 h e a d head head。
踢队尾
我们首先一定要确定 i i i这个状态,要优于 q t a i l q_{tail} qtail
要维护的队列由于 q t a i l − 1 q_{tail-1} qtail−1一定优于 q t a i l q_{tail} qtail
现有一个标准值 x b t ( t a i l < t ) x_{b_t}(tail<t) xbt(tail<t)
c a l c ( q t a i l − 1 , q t a i l ) ≥ x b t calc(q_{tail-1},q_{tail)}\ge x_{b_t} calc(qtail−1,qtail)≥xbt
如果 q t a i l q_{tail} qtail要优于 i i i,
则 c a l c ( q t a i l , i ) ≥ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\ge calc(q_{tail-1},q_{tail}) calc(qtail,i)≥calc(qtail−1,qtail)
才能确保 q t a i l q_{tail} qtail优于 i i i
反之,当 c a l c ( q t a i l , i ) ≤ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\le calc(q_{tail-1},q_{tail}) calc(qtail,i)≤calc(qtail−1,qtail)时,需要删去队尾。
貌似就没了哦。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define gc getchar()
#define ll long long
using namespace std;
const int N=5e4+10;
inline void qr(ll &x)
{
x=0;int f=1;char c=gc;
while(c<'0'||c>'9')c=gc;
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(ll x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
struct node
{
ll x,y;
}a[N];
bool cmp(node a,node b){return a.x==b.x?a.y<b.y:a.x<b.x;}
ll f[N];int b[N],q[N],l,r;
inline double calc(int j,int k){return (f[j]-f[k])/(double)(a[b[k+1]].y-a[b[j+1]].y);}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)qr(a[i].x),qr(a[i].y);
sort(a+1,a+n+1,cmp);
int tot=0;
for(int i=1;i<=n;i++)
{
while(tot&&a[b[tot]].y<=a[i].y)--tot;
b[++tot]=i;
}
l=1;r=1;q[1]=0;
for(int i=1;i<=tot;i++)
{
while(l<r&&calc(q[l],q[l+1])<=1.0*a[b[i]].x)++l;
f[i]=f[q[l]]+a[b[i]].x*a[b[q[l]+1]].y;
while(l<r&&calc(q[r],i)<=calc(q[r-1],q[r]))--r;
q[++r]=i;
}
qw(f[tot]);puts("");
return 0;
}