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

    1096: [ZJOI2007]仓库建设

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 4201  Solved: 1851
    [Submit][Status][Discuss]

    Description

      L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。由于这座山处于高原内
    陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L公司的总裁L先生接到气象
    部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。由于
    地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库
    的费用是Ci。对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外销售处设
    置在山脚的工厂N,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的,
    假设一件产品运送1个单位距离的费用是1。假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到
    以下数据:1:工厂i距离工厂1的距离Xi(其中X1=0);2:工厂i目前已有成品数量Pi;:3:在工厂i建立仓库的费用
    Ci;请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。

    Input

      第一行包含一个整数N,表示工厂的个数。接下来N行每行包含两个整数Xi, Pi, Ci, 意义如题中所述。

    Output

      仅包含一个整数,为可以找到最优方案的费用。

    Sample Input

    3
    0 5 10
    5 3 100
    9 6 10

    Sample Output

    32

    HINT

    在工厂1和工厂3建立仓库,建立费用为10+10=20,运输费用为(9-5)*3 = 12,总费用32。如果仅在工厂3建立仓库,建立费用为10,运输费用为(9-0)*5+(9-5)*3=57,总费用67,不如前者优。

    【数据规模】

    对于100%的数据, N ≤1000000。 所有的Xi, Pi, Ci均在32位带符号整数以内,保证中间计算结果不超过64位带符号整数。 


    总结一下普通斜率优化题的过程吧:

    f[i]=min{f[j]+c[i]+p[j+1]*(x[i]-x[j+1])+p[j+2]*(x[i]-x[j+2])}

    处理p和x*p的前缀和

    然后化啊化,

    slope(j,k)=(double)(g[k]-g[j]+f[k]-f[j])/(double)(p[k]-p[j])

    得到j<k,slope(j,k)<x[i]时k更优

    判断一下发现x<y<z,slope(x,y)>slope(y,z)时y不是最优

    是一个下凸壳

    因为p和g单增,单调队列维护就行了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N=1e6+5,INF=1e9;
    typedef long long ll;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    ll n,p[N],g[N],x[N],c[N];
    ll f[N];
    inline double slope(int j,int k){
        return (double)(g[k]-g[j]+f[k]-f[j])/(double)(p[k]-p[j]);
    }
    int q[N],head,tail;
    void dp(){
        head=tail=1;
        for(int i=1;i<=n;i++){
            while(head<tail&&slope(q[head],q[head+1])<=x[i]) head++;
            int j=q[head];
            f[i]=x[i]*(p[i]-p[j])-(g[i]-g[j])+c[i]+f[j];
            while(head<tail&&slope(q[tail-1],q[tail])>slope(q[tail],i)) tail--;
            q[++tail]=i;
        }        
        printf("%lld",f[n]);
    }
    int main(){
        //freopen("in.txt","r",stdin);
        n=read();
        for(int i=1;i<=n;i++){
            x[i]=read();p[i]=read();c[i]=read();
            g[i]=g[i-1]+x[i]*p[i];p[i]+=p[i-1];
        }
        dp();
    }
  • 相关阅读:
    python中的编码问题
    CVPR2018 Tutorial 之 Visual Recognition and Beyond
    hdu 1376 Octal Fractions
    hdu 1329 Hanoi Tower Troubles Again!
    hdu 1309 Loansome Car Buyer
    hdu 1333 Smith Numbers
    hdu 1288 Hat's Tea
    hdu 1284 钱币兑换问题
    hdu 1275 两车追及或相遇问题
    hdu 1270 小希的数表
  • 原文地址:https://www.cnblogs.com/candy99/p/6260286.html
Copyright © 2011-2022 走看看