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


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1597

    题意:

      有n块矩形土地,长为a[i],宽为b[i]。

      FJ想要将这n块土地全部买下来。

      土地可以分组购买。

      若有某一些土地被分到了一组,则将这一组土地全部买下的花费为他们的max(a[i])*max(b[i])。

      问你最小总花费是多少。

    题解:

      首先,如果一块土地能够被另一块土地完全包含(即长宽都比另一个小),那么被包含的那块土地可以忽略不计。

      然后贪心地考虑如何使花费最小:

        如果要使花费尽可能小,则分在同一组中矩形的长宽差距应尽可能地小。

      所以将长a[i]作为第一关键字,将宽b[i]作为第二关键字排序。

      此时矩形的长a[i]一定是非降的,那么对于两个矩形i和j(i<j),如果有b[i]<=b[j],则j一定能完全包含i。

      利用这一特性将所有能被包含的矩形去掉。

      此时矩形的宽b[i]就变成了严格递减的了。

      显然,此时分到一组中的矩形必须是连续的一段区间,才有可能最优。

      然后就可以dp了。

      表示状态:

        dp[i]表示已经购买了前i块土地的最小花费。

      找出答案:

        假设去掉能被包含的矩形之后,矩形总数为tot。

        ans = dp[tot]

      如何转移:

        dp[i] = min dp[j] + a[i]*b[j+1]

      边界条件:

        dp[0] = 0

      斜率优化:

        设j < k,且k的决策更优。

        则:dp[j] + a[i]*b[j+1] > dp[k] + a[i]*b[k+1]

        整理得:(dp[k]-dp[j])/(b[j+1]-b[k+1]) < a[i]

        所以slope(i,j) = (dp[i]-dp[j])/(b[j+1]-b[i+1])

        由于a[i]非降,所以用单调队列维护下凸壳即可。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <algorithm>
     5 #define MAX_N 50005
     6 
     7 using namespace std;
     8 
     9 struct Rect
    10 {
    11     long long a,b;
    12     Rect(long long _a,long long _b)
    13     {
    14         a=_a; b=_b;
    15     }
    16     Rect(){}
    17     friend bool operator < (const Rect &x,const Rect &y)
    18     {
    19         return x.a!=y.a ? x.a<y.a : x.b<y.b;
    20     }
    21 };
    22 
    23 int n;
    24 int q[MAX_N];
    25 long long dp[MAX_N];
    26 Rect x[MAX_N];
    27 
    28 void read()
    29 {
    30     cin>>n;
    31     for(int i=1;i<=n;i++)
    32     {
    33         cin>>x[i].a>>x[i].b;
    34     }
    35 }
    36 
    37 inline double slope(int i,int j)
    38 {
    39     return (double)(dp[i]-dp[j])/(x[j+1].b-x[i+1].b);
    40 }
    41 
    42 void work()
    43 {
    44     sort(x+1,x+1+n);
    45     int tot=0;
    46     for(int i=1;i<=n;i++)
    47     {
    48         while(tot && x[i].b>=x[tot].b) tot--;
    49         x[++tot]=x[i];
    50     }
    51     x[tot+1]=Rect(0,0);
    52     int l=1,r=1;
    53     q[1]=0,dp[0]=0;
    54     for(int i=1;i<=tot;i++)
    55     {
    56         while(l<r && slope(q[l],q[l+1])<=x[i].a) l++;
    57         dp[i]=dp[q[l]]+x[i].a*x[q[l]+1].b;
    58         while(l<r && slope(q[r],i)<slope(q[r-1],q[r])) r--;
    59         q[++r]=i;
    60     }
    61     cout<<dp[tot]<<endl;
    62 }
    63 
    64 int main()
    65 {
    66     read();
    67     work();
    68 }
  • 相关阅读:
    2018-08-07
    2018-08-06
    2018-08-03
    安装mysql
    iOS-----------关于组件化
    QQ路径
    iOS----------viewcontroller中的dealloc方法不调用
    【2020Python修炼记】前端开发之 JavaScript 的 BOM 和 DOM 操作
    【2020Python修炼记】前端开发之 JavaScript 内置方法
    【2020Python修炼记】前端开发之 JavaScript 函数
  • 原文地址:https://www.cnblogs.com/Leohh/p/8409689.html
Copyright © 2020-2023  润新知