• 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 }
  • 相关阅读:
    初始ASP.NET数据控件【续 DataList】
    初始ASP.NET数据控件GridView
    初始ADO.NET数据操作
    初识 Asp.Net数据验证控件
    【Socket编程】Java通信是这样炼成的
    JAVA之I/O 输入输出流详解
    浅入深出之Java集合框架(下)
    浅入深出之Java集合框架(中)
    浅入深出之Java集合框架(上)
    全面解释java中StringBuilder、StringBuffer、String类之间的关系
  • 原文地址:https://www.cnblogs.com/Leohh/p/8407247.html
Copyright © 2020-2023  润新知