• BZOJ 1597: [Usaco2008 Mar]土地购买


    Time Limit: 10 Sec Memory Limit: 162 MB
    Submit: 6061 Solved: 2298
    [Submit][Status][Discuss]
    Description

    农夫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.

    题解

    玄学斜率优化,首先我们可以将那些“免费送的地”去了,免费送就是将它按长度降序排序,维护一个宽度
    递增的序列,那些去掉的即是免费送的。然后我们考虑转移方程,因为此时的w单调递增,l单调递减。
    f[i]=min(f[j]+l[j+1]*w[i])
    然后我们再YY出一个k,使得k<j且f[j]更优。
    f[j]+l[j+1]*w[i]<f[k]+l[k+1]*w[i],整理得
    (f[j]-f[k])/(l[k+1]-l[j+1])>w[i],我们将前面的式子当做斜率,每次判断斜率是否大于新增宽度,
    维护一个单调队列,然后用队头更新。
    

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    const int MAXN = 50005;
    
    inline int rd(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    
    struct Ground{
        int l,w;
    }g[MAXN],gr[MAXN];
    
    int n,cnt;
    int Q[MAXN],head=1,tail=1;
    long long f[MAXN];
    
    inline bool cmp(Ground x,Ground y){
        if(x.l==y.l) return x.w>y.w;
        return x.l>y.l;
    }
    
    inline double slope(int x,int y) {
        return (double)(f[x]-f[y])/(double)(gr[y+1].l-gr[x+1].l);
    }
    
    int main(){
        n=rd();
        for(register int i=1;i<=n;i++){
            g[i].l=rd();
            g[i].w=rd();
        }
        sort(g+1,g+1+n,cmp);
        for(register int i=1;i<=n;i++){
            if(g[i].w<=gr[cnt].w) continue;
            gr[++cnt].l=g[i].l;
            gr[cnt].w=g[i].w;
        }
        for(register int i=1;i<=cnt;i++){
            while(head<tail && slope(Q[head],Q[head+1])<=gr[i].w) head++; 
            f[i]=f[Q[head]]+(long long)gr[i].w*gr[Q[head]+1].l;
            while(head<tail && slope(Q[tail-1],Q[tail])>=slope(Q[tail],i)) tail--;
            Q[++tail]=i;
        }
        printf("%lld",f[cnt]);
        return 0;
    }
  • 相关阅读:
    20155327 嵌入式C语言课堂补交
    2017-2018-1 20155327 《信息安全系统设计基础》课程总结
    2017-2018-1 20155327 《信息安全系统设计基础》第十四周学习总结
    2017-2018-1 20155327 实验五 通讯协议设计
    2017-2018-1 20155327 《信息安全系统设计基础》第十三周学习总结
    《Java程序设计》课堂实践内容总结
    20155337 2016-2017-2《Java程序设计》课程总结
    20155337 《网络安全编程》实验五实验报告
    # 20155337 《Android程序设计》实验四实验报告
    20155337 《Java程序设计》实验三(敏捷开发与XP实践)实验报告
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9677028.html
Copyright © 2020-2023  润新知