zoukankan      html  css  js  c++  java
  • [BZOJ1597]土地购买

    [BZOJ1597]土地购买

    题面

    农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <

    = 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价

    格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要

    付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

    Input

    * 第1行: 一个数: N

    * 第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽

    Output

    * 第一行: 最小的可行费用.

    Sample Input

    4
    100 1
    15 15
    20 5
    1 100
    输入解释:
    共有4块土地.

    Sample Output

    500
    FJ分3组买这些土地:
    第一组:100x1,
    第二组1x100,
    第三组20x5 和 15x15 plot.
    每组的价格分别为100,100,300, 总共500.

    思路

    很显然,如果土地A被土地B包含,那么我们可以直接舍弃土地A不管。考虑如何判断包含关系。

    先将所有土地按照长度从大到小排序。然后依次把土地放入一个新数组。需要注意的是,如果当前放入的土地的宽度小于等于数组中的最后一块土地,那么就可以直接舍弃当前土地,不用放入数组(被包含)。

    那么观察一下我们得到的新数组,发现其长度是单调递减的,宽度是单调递增的。那么我们可以很容易的想到状态转移方程:

    [f[i]=min(f[j]+length[j+1]*width[i]),1 leq j < i ]

    直接暴力转移复杂度(O(n^2))肯定是要炸的。考虑使用斜率优化:

    [令x=width[i],k=length[j+1],b=f[j] \f[j]+length[j+1]*width[i]=kx+b ]

    所以问题就转化为了作一条直线(x=f[i]),求所有直线与之交点中纵坐标最小的那一个点。

    总结一下,斜率优化必须符合这几个条件:

    • k具有单调性
      //未完待续

    代码

    注意,每次while(...){head++;}之后的head不是找到的最优解(j)。而是线段对应的编号。因为可能舍去一些线段,所以线段对应的编号是小于等于线段对应的(j)的。

    另外,写状态转移方程的时候取值范围应该保证(<i)而不是(leq i)。因为我们是先查询再插入的,所以在查询时是取不到(i)的。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 55000
    #define ll long long
    struct line{
        ll k,b;
    }l[maxn];
    struct field{
        int wid,len;
    }fie1[maxn],fie2[maxn];
    int n,head=1,tail,cntn;
    ll f[maxn];
    bool cmp(field x,field y){
        if(x.len==y.len){return x.wid>y.wid;}
        return x.len>y.len;
    }
    bool calc(line l1,line l2,int c){return (double)(l1.b-l2.b)/(l2.k-l1.k)<=c;}
    bool calc(line l1,line l2,line now){return
        (double)(l1.b-l2.b)/(l2.k-l1.k)>=(double)(l1.b-now.b)/(now.k-l1.k);}
    int main(){
        //freopen("in","r",stdin);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d%d",&fie1[i].wid,&fie1[i].len);
        sort(fie1+1,fie1+1+n,cmp);
        for(int i=1;i<=n;i++){
            if(fie1[i].wid>fie2[cntn].wid){fie2[++cntn]=fie1[i];}
        }
        n=cntn;l[++tail]=(line){fie2[1].len,0};//l[1].k=fie2[1].len;
        for(int i=1;i<=n;i++){
            while(head<tail&&calc(l[head],l[head+1],fie2[i].wid))head++;
            f[i]=l[head].k*fie2[i].wid+l[head].b;
            line now=(line){fie2[i+1].len,f[i]};
            while(head<tail&&calc(l[tail],l[tail-1],now))tail--;
            l[++tail]=now;
        }
        printf("%lld",f[n]);
        return 0;
    }
    
  • 相关阅读:
    jmeter(46) redis
    jmeter(45) tcp/ip协议
    Codeforces Round #538 (Div. 2)D(区间DP,思维)
    Codeforces Global Round 1D(DP,思维)
    Educational Codeforces Round 57D(DP,思维)
    UPC11073(DP,思维)
    Yahoo Progamming Contest 2019D(DP,思维)
    Atcoder Beginner Contest 118D(DP,完全背包,贪心)
    Xuzhou Winter Camp 1C(模拟)
    Educational Codeforces Round 57 (Rated for Div. 2)D(动态规划)
  • 原文地址:https://www.cnblogs.com/GavinZheng/p/10948031.html
Copyright © 2011-2022 走看看