BZOJ[1597][Usaco2008 Mar]土地购买 斜率优化

12 篇文章 0 订阅
5 篇文章 0 订阅

传送门ber~

首先按 x x 为第一关键字,y为第二关键字,将没有贡献的矩形( xi<xj,yi<yj,i<j x i < x j , y i < y j , i < j )删掉,这样就满足了 x x 递增,y递减,列出dp方程 fi=min{fj+yj+1xi} f i = m i n { f j + y j + 1 ∗ x i }
t>k t > k ,状态 t t k优,当且仅当

ft+yt+1xi<fk+yk+1xi f t + y t + 1 ∗ x i < f k + y k + 1 ∗ x i

因为 y y 递减,所以yk+1yt+1>0,那么
ftfkyk+1yt+1<xi f t − f k y k + 1 − y t + 1 < x i
ftfkyt+1yk+1>xi f t − f k y t + 1 − y k + 1 > − x i

所以维护一个上凸壳,坐标为 (yi+1,fi) ( y i + 1 , f i ) ,斜率优化。
x x <script type="math/tex" id="MathJax-Element-1367">x</script>是单调的,所以单调队列维护

代码如下:

#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define INF 21474836470000ll
#define N 50050
using namespace std;
typedef long long LL;
inline int read(){
    int x=0,f=1;char c;
    do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
    return x*f;
}
int n,l,r,tot;
LL f[N];
struct Point{
    LL x,y;
    Point(){}
    Point(LL _,LL __):x(_),y(__){}
}q[N],a[N],b[N],tmp;
inline bool cmp(Point a,Point b){
    return a.x==b.x?a.y<b.y:a.x<b.x;
}
inline double Slop(Point a,Point b){
    if(a.x==b.x) return a.y>b.y?-INF:INF;
    return 1.0*(b.y-a.y)/(b.x-a.x);
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
        b[i].x=read();b[i].y=read();
    }
    sort(b+1,b+n+1,cmp);
    for(int i=1;i<=n;i++){
        while(tot && b[i].y>=a[tot].y) tot--;
        a[++tot]=b[i];
    }
    l=r=0;
    q[0]=Point(a[1].y,0);
    for(int i=1;i<=tot;i++){
        while(l<r && Slop(q[l],q[l+1])>-a[i].x) l++;
        f[i]=a[i].x*q[l].x+q[l].y;
        tmp=Point(a[i+1].y,f[i]);
        while(l<r && Slop(q[r],tmp)>Slop(q[r-1],q[r])) r--;
        q[++r]=tmp;
    }
    printf("%lld",f[tot]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值