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 }

 

posted @ 2018-02-03 15:51  Leohh  阅读(151)  评论(0编辑  收藏  举报