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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1096

    首先得到dp方程(我竟然自己都每推出了QAQ)$$d[i]=min{d[j]+cost(j+1,i)}+c[i]$$其中$d[i]$是前i个且在i建仓库的最小费用,$cost(j+1,i)$是将j+1~i的东西全都运到i的费用

    而我们先考虑cost怎么求,orz,好神的前缀和,首先维护sum[i]表示1~i的物品,则j~i的东西从j全都运到i需要$$(sum[i]-sum[j])  imes x[i]$$,然后再设前缀和b[i]表示1~i的物品每一个i从1运到i的费用,则$$cost[j+1,i]=(sum[i]-sum[j])  imes x[i]-(b[i]-b[j])$$其中$$sum[i]=sum[i-1]+p[i], b[i]=b[i-1]+p[i]  imes x[i]$$

    然后方程变成$$d[i]=min{d[j]+(sum[i]-sum[j])  imes x[i]-(b[i]-b[j])}+c[i]$$化简一下可得$$d[i]=min{d[j]+b[j]-x[i] imes sum[j])}+c[i]+sum[i] imes x[i]-b[i]$$

    而对于这种方程,显然斜率优化。

    而斜率优化有几个技巧:

    1、不用1D1D直接上斜率,用通俗易懂的方法:

    假设决策j<k且k比j优,即:

    $$d[k]+b[k]-x[i] imes sum[k]<d[j]+b[j]-x[i] imes sum[j]$$

    化简成:

    $$frac{d[k]+b[k]-d[j]-b[j]}{sum[k]-sum[j]}<x[i]$$

    因为x[i]单调递增,所以当任意i<L,满足上边不等式,即决策k比j优(在i情况下k比j优的情况时),任意i<L的决策总是大于等于k的,所以当i取最优决策时,i<L的决策单调不降

    接下来就是坐标轴的x单调递增,即根据上式,我们可以将点看做(sum[k], d[k]-b[k]),所以可以得到那个斜率方程,这样显然作为坐标轴x的sum[k]是单调不降的,所以得证。

    因此这些决策就是二维平面上的点集,想象斜率为x[i]的直线从负无穷向正无穷扫,碰到的第一个点就是最优点(及凸包上的点),理由很简单,因为我们有上边那个不等式,凸包上的点k到任意点j<k的斜率总小于其它不在凸包上的点到任意点的斜率,即k为最优。

    那么就维护一个单调队列,斜率递增,然后向求凸包的算法一样在队尾维护凸包即可。

    2、论文《1D1D动态规划优化初步》上的做法(其实1的做法是这种做法的简便形式)

    而之前的某题:【BZOJ】1010: [HNOI2008]玩具装箱toy(dp+斜率优化)

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    typedef long long ll;
    #define pii pair<int, int>
    #define mkpii make_pair<int, int>
    #define pdi pair<double, int>
    #define mkpdi make_pair<double, int>
    #define pli pair<ll, int>
    #define mkpli make_pair<ll, int>
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define error(x) (!(x)?puts("error"):0)
    #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
    #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '	'; cout << endl
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=1000005;
    int n, q[N], front, tail;
    ll x[N], p[N], c[N], sum[N], b[N], f[N];
    #define F(x) (f[x]+b[x])
    #define E(k,j) (F(k)-F(j))
    #define S(k,j) (sum[k]-sum[j])
    
    int main() {
    	read(n);
    	for1(i, 1, n) read(x[i]), read(p[i]), read(c[i]);
    	for1(i, 1, n) sum[i]=sum[i-1]+p[i];
    	for1(i, 1, n) b[i]=b[i-1]+p[i]*x[i];
    	tail=1;
    	for1(i, 1, n) {
    		while(front<tail-1 && E(q[front+1], q[front])<x[i]*S(q[front+1], q[front])) ++front;
    		int j=q[front];
    		f[i]=f[j]+(sum[i]-sum[j])*x[i]-(b[i]-b[j])+c[i];
    		while(front<tail-1 && E(q[tail-1], q[tail-2])*S(i, q[tail-1])>E(i, q[tail-1])*S(q[tail-1], q[tail-2])) --tail;
    		q[tail++]=i;
    	}
    	printf("%lld", f[n]);
    	return 0;
    }
    

      


    Description

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

    Source

  • 相关阅读:
    HBase(九)HBase表以及Rowkey的设计
    iOS-动态库创建(详解)
    组件化-动态库实战
    Xcode创建子工程以及工程依赖
    XMPP详解
    iOS中WebKit框架应用与解析
    HYStockChart, 股票图(包括K线图、趋势图、成交量、滚动、放大缩小等)
    OC与JS交互
    iOS 与 js交互的其一方法 WebViewJavascriptBridge的使用
    OC和JS调用
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4108902.html
Copyright © 2011-2022 走看看