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

土 地 购 买 土地购买

题目描述见链接 .


正 解 部 分 \color{red}{正解部分}

将 矩形的 作为 x x x, 矩形的 作为 y y y, 放到 平面直角坐标系 中,
题目转化 为使用 最小的矩阵面积和 覆盖所有点,

可以发现当矩形 a , b a, b a,b 满足 a . x ≤ b . x a.x \le b.x a.xb.x a . y ≤ b . y a.y \le b.y a.yb.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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值