zoukankan      html  css  js  c++  java
  • luogu2900 购买土地

    题目描述

    Farmer John 准备扩大他的农场,眼前他正在考虑购买 N 块长方形的土地。

    如果 FJ 单买一块土地,价格就是土地的面积。但他可以选择并购一组土地,并购的价格为这些土地中最大的长乘以最大的宽。比如 FJ 并购一块 3×5 和一块 5×3 的土地,他只需要支付 5×5=25 元, 比单买合算。

    FJ 希望买下所有的土地。他发现,将这些土地分成不同的小组来并购可以节省经费。 给定每份土地的尺寸,请你帮助他计算购买所有土地所需的最小费用。

    输入格式

    第一行一个整数 N1N5×10^4)。

    接下来 N 行,每行两个整数 w_i 和 l_i,代表第 i 块土地的长和宽。保证土地的长和宽不超过 10^6

    输出格式

    输出买下所有土地的最小费用。

    输入输出样例

    输入 #1
    4 
    100 1 
    15 15 
    20 5 
    1 100 
    
    输出 #1
    500 

    说明/提示

    将所有土地分为三组:

    • 第一块土地为第一组,花费 100×1=100;
    • 第二,三块土地为第二组,花费 20×15=300;
    • 第四块土地为第三组,花费 1×100=100;

    总花费为 500,可以证明不存在更优的方案。

    ________________________________________

    简单的斜率优化动态规划

    首先,如果一块的长宽都大于等于另一块地,那么另一块地是不需要交钱的。所以先把所有的土地按照长从大到小排序,如果后面的土地的宽度小于前面某块大的,则不需考虑。

    剩余的土地的宽逐步减小,而长逐渐增加的(减小的都不用考虑)。

    建立简单的动态规划:f[i]=min(f[j]+h[i]*w[j+1])

    这个动归要依次从大到小枚举i,而每个i要枚举j,所以明显是O(N^2),无法完成。

    由于出现了h[i]*w[j+1],而求得是最小值,因此考虑斜率优化。

    设:0<j<k<i,且k优于j

    所以,f[j]+h[i]*w[j+1]>f[k]+h[i]*w[k+1]

    移项可得:(f[k]-f[j])/(w[k+1]-w[j+1])>-h[i]

    我们通过前面的排序可知:h[i]是逐渐变大的,所以-h[i]逐渐减小,具有单调性

    然后就按照斜率优化做就可以了!

    ________________________________________

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=5e4+10;
     4 struct node
     5 {
     6     long long w,h;
     7 }sz[maxn];
     8 int n;
     9 int q[maxn];
    10 long long f[maxn];
    11 bool cmp(node a,node b)
    12 {
    13     return a.w>b.w || a.w==b.w &&a.h>b.h;
    14 }
    15 long double y(int a)
    16 {
    17     return (double)f[a];
    18 }
    19 long double x(int a)
    20 {
    21     return (double)sz[a+1].w;
    22 }
    23 long double get_xl(int a,int b)
    24 {
    25     return (y(b)-y(a))/(x(b)-x(a));    
    26 }
    27 
    28 int main()
    29 {
    30     scanf("%d",&n);
    31     for(int i=1;i<=n;++i)
    32         scanf("%lld%lld",&sz[i].w,&sz[i].h);
    33     sort(sz+1,sz+1+n,cmp);
    34     int nn=1;
    35     for(int i=2;i<=n;++i)
    36         if(sz[i].h>sz[nn].h)sz[++nn]=sz[i];
    37     int l,r;
    38     l=r=0;
    39     for(int i=1;i<=nn;++i)
    40     {
    41         while(l<r && get_xl(q[l],q[l+1])>=-sz[i].h)l++;
    42         f[i]=f[q[l]]+sz[i].h*sz[q[l]+1].w;
    43         while(l<r && get_xl(q[r-1],q[r])<=get_xl(q[r],i))--r;
    44         q[++r]=i;
    45     }
    46     cout<<f[nn]<<endl;
    47     return 0;
    48 }
    View Code
  • 相关阅读:
    win10自带邮箱应用无法查看qq邮箱应用解决办法
    Ubuntu紫色背景颜色代码
    VMware中对Linux虚拟机的网络配置静态IP的配置
    CentOS 7在VMware 12中共享文件看不见的问题?
    C++中让人忽视的左值和右值
    C++ allocator类学习理解
    C++11新特性 -----> 右值引用 &&
    重新认识new
    关于C++中nothrow的某某某
    stopPropagation, preventDefault 和 return false 的区别
  • 原文地址:https://www.cnblogs.com/gryzy/p/14356694.html
Copyright © 2011-2022 走看看