[斜率DP优化]BZOJ 1597: [Usaco2008 Mar]土地购买 题解

(传送门)

题目描述

给出n块土地,第i块长度为 xi ,宽度为 yi ,一次可以购买任意数目土地,每次购买的价格为所有这次购买的土地中 max{xi}max{yi} ,求购买全部土地最少需要多少钱。

解题分析

首先对于一块土地i,如果存在另一块土地j,有 xj>xi,yj>yi ,那么说明i不可能对答案会有影响,所以可以筛去i,所以可以预处理所有的土地,筛去所有不符合规格的,剩下的土地才是我们要考虑的有可能会对答案产生影响的。这个土地序列满足 xi 递减 yi 递增。

然后发现是线性DP, f[i]=min{f[j]+y[i]x[j+1]} ,然后又发现i和j关系有相乘的,就考虑线性DP。
f[j]+y[i]x[j+1]<f[k]+y[i]x[k+1]
f[j]f[k]<y[i](r[k+1]r[j1])
f[j]f[k]r[k+1]r[j+1]<c[i]
然后就直接套模板就行了。

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
struct data{
    int x,y;
    bool operator < (const data b)const{
        return x>b.x||(x==b.x&&y>b.y);
    }
}a[50005];
int n,m,que[50005],hed,til;
LL f[50005];
inline void readi(int &x){
    x=0; char ch=getchar();
    while ('0'>ch||ch>'9') ch=getchar();
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
LL getX(const int i,const int j){return a[i+1].x-a[j+1].x;}
LL getY(const int i,const int j){return f[j]-f[i];}
int main()
{
    freopen("buy.in","r",stdin);
    freopen("buy.out","w",stdout);
    readi(m); n=hed=til=0;
    for (int i=1;i<=m;i++) {readi(a[i].x); readi(a[i].y);} sort(a+1,a+m+1);
    for (int i=1,mx=0;i<=m;i++) if (mx<a[i].y) {mx=a[i].y; a[++n]=a[i];}
    hed=til=1; que[1]=f[0]=0;
    for (int i=1;i<=n;i++){
        while (hed<til&&getY(que[hed],que[hed+1])<=getX(que[hed],que[hed+1])*a[i].y) hed++;
        f[i]=f[que[hed]]+(LL)a[i].y*a[que[hed]+1].x;
        while (hed<til&&getY(que[til-1],que[til])*getX(que[til],i)>=getX(que[til-1],que[til])*getY(que[til],i)) til--;
        que[++til]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/try__jhf/article/details/78293840