zoukankan      html  css  js  c++  java
  • BZOJ 1096 [ZJOI2007]仓库建设:斜率优化dp

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

    题意:

      有n个工厂,从左往右排成一排,分别编号1到n。

      每个工厂里有p[i]件产品,到1号工厂的距离为x[i],在此处建一个仓库的花费为c[i]。

      现在你需要建造一些仓库,使得所有产品都被运送到仓库中来。

      产品只能从左往右运输。每一件产品运输一个单位距离的花费为1。

      问你最小总花费(运输费 + 建仓库花费)。

     

    题解:

      表示状态:

        dp[i]表示在工厂i建了一个仓库,并且仓库1 to i中的产品都已经被运到仓库中了,此时的最小总花费。

      找出答案:

        ans = dp[n]

        因为无论如何都必须在工厂n处建一个仓库。

      如何转移:

        dp[i] = min dp[j] + ∑(p[k]*(x[i]-x[k])) + c[i]

        (j < i, k = j+1 to i)

        定义前缀和数组:sp[i] = ∑ p[j], s[i] = ∑(x[j]*p[j])

        (j = 1 to i)

        则原转移方程可化简为:

          dp[i] = min dp[j] + x[i]*(sp[i]-sp[j]) - s[i] + s[j] + c[i]

      边界条件:

        dp[0] = 0

      斜率优化:

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

        则有:dp[j] + x[i]*(sp[i]-sp[j]) + s[j]> dp[k] + x[i]*(sp[i]-sp[k]) + s[k]

        整理得:(dp[j]+s[j]-dp[k]-s[k]) / (sp[j]-sp[k]) < x[i]

        (注意:因为sp[j]-sp[k]<0,所以除过来之后不等式要变号)

        所以slope(i,j) = (dp[i]+s[i]-dp[j]-s[j]) / (sp[i]-sp[j])

        由于x[i]递增,所以用单调队列维护下凸壳即可。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 1000005
     5 #define INF 1000000000
     6 
     7 using namespace std;
     8 
     9 int n;
    10 int q[MAX_N];
    11 long long x[MAX_N];
    12 long long p[MAX_N];
    13 long long c[MAX_N];
    14 long long s[MAX_N];
    15 long long dp[MAX_N];
    16 
    17 void read()
    18 {
    19     cin>>n;
    20     memset(s,0,sizeof(s));
    21     memset(p,0,sizeof(p));
    22     for(int i=1;i<=n;i++)
    23     {
    24         cin>>x[i]>>p[i]>>c[i];
    25         s[i]=s[i-1]+x[i]*p[i];
    26         p[i]+=p[i-1];
    27     }
    28 }
    29 
    30 inline double slope(int i,int j)
    31 {
    32     return (double)(dp[i]+s[i]-dp[j]-s[j])/(p[i]-p[j]);
    33 }
    34 
    35 void work()
    36 {
    37     int l=1,r=1;
    38     q[1]=0,dp[0]=0;
    39     for(int i=1;i<=n;i++)
    40     {
    41         while(l<r && slope(q[l],q[l+1])<=x[i]) l++;
    42         dp[i]=dp[q[l]]+x[i]*(p[i]-p[q[l]])-s[i]+s[q[l]]+c[i];
    43         while(l<r && slope(q[r],i)<slope(q[r-1],q[r])) r--;
    44         q[++r]=i;
    45     }
    46     cout<<dp[n]<<endl;
    47 }
    48 
    49 int main()
    50 {
    51     read();
    52     work();
    53 }
  • 相关阅读:
    【java】报错could not find the main class,program will
    CSS3——阴影
    SSO单点登录系列2:cas客户端和cas服务端交互原理动画图解,cas协议终极分析
    SSO单点登录系列3:casserver端配置认证方式实践
    [转载] jQuery Mobile 开发 Web App 系列文章目录
    SHELL基本语法2
    SHELL编程基本语法
    如何写批处理文件
    LINUX shell-快速参考[一]
    Shell中的引号,反引号,双引号,反斜杠
  • 原文地址:https://www.cnblogs.com/Leohh/p/8407247.html
Copyright © 2011-2022 走看看