• 【BZOJ】【1096】【ZJOI2007】仓库建设


    DP/斜率优化


      Orz Hzwer

    八中好像挂了……明天再提交吧……

    UPD:2015-03-12 17:24:43

      算了,毕竟是第一道题,还是仔细写一下斜率优化的过程吧。(部分引自Hzwer的题解)

      首先我们根据题意可以列出动规方程 $$ f[i]=min{ f[j]+cal(j,i) }$$

      处理$cal(j,i)$可以利用前缀和的思想,令$ sum[i]=sum_{k=1}^{i} p[k] $

      对于物品$1 ~ i$,如果都从$0$运到$i$,则费用为$(sum[i]-sum[j])*x[i]$

      但由于物品的起始点不都在0,所以对于每个物品$k$可以少花费$x[k]*p[k]$

      定义$b[i]=sum_{k=1}^{i} (x[k]*p[k]) $

      可得 $ f[i]=min{ f[j]+(sum[i]-sum[j])*x[i]-(b[i]-b[j])+c[i] } $

      下面证明决策单调性:

        如果$ j > k $ 且$j$比$k$更优,则有:

    [ egin{aligned} f[j]+(sum[i]-sum[j])*x[i]-(b[i]-b[j])+c[i] &< f[k]+(sum[i]-sum[j])*x[i]-(b[i]-b[k])+c[i] \ f[j]-f[k]+b[j]-b[k] &< (sum[j]-sum[k])*x[i] \ frac{f[j]-f[k]+b[j]-b[k]}{sum[j]-sum[k]} &< x[i] end{aligned} ]

      至于为什么要证这个东西请看论文:《动态规划的斜率优化》

      嗯我们现在就知道了对于每个状态$i$,从1 ~ i-1这些决策中的“当前最优决策”是有一个单调性的!比如我们从1开始枚举到 k ,发现 k 是一个最优决策可以更新答案f[i],然后我们继续枚举直到决策 j ,满足上面那个不等式!则表明决策 j 比决策 k 更优!那么有什么用呢?我们根据不等式发现,这个“更优”的属性,只跟 j 和 k 有关,与阶段 i 是无关的!也就是说,当 j 成为一个可选的方案的时候,k 就永远也不用再考虑它了,这就大大减少了转移时的决策数!从而降低了复杂度!

      说的好像很厉害……那具体操作的时候怎么操作呢?

      我们用一个队列q来维护一个斜率单调的决策序列:

     如果slop(q[l],q[l+1])<x[i](参考上面推出的不等式)则说明q[l+1]这个决策比q[l]这个决策更优,所以l++舍弃队首

     算出dp[i]

     如果slop(q[r-1],q[r])>slop(q[r],i),则队尾处不满足单调,所以要弹队尾直到满足单调性(联系凸壳的图形想想)

     插入决策 i 到队列尾部

      当然如果换了一道求max的题,则不等号方向是要改变的……

     1 /**************************************************************
     2     Problem: 1096
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:1784 ms
     7     Memory:52052 kb
     8 ****************************************************************/
     9  
    10 //BZOJ 1096
    11 #include<cstdio>
    12 #include<iostream>
    13 #include<algorithm>
    14 #define rep(i,n) for(int i=0;i<n;++i)
    15 #define F(i,j,n) for(int i=j;i<=n;++i)
    16 #define D(i,j,n) for(int i=j;i>=n;--i)
    17 #define pb push_back
    18 using namespace std;
    19 int getint(){
    20     int v=0,sign=1; char ch=getchar();
    21     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    22     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    23     return v*sign;
    24 }
    25 const int N=1000010;
    26 typedef long long LL;
    27 /******************tamplate*********************/
    28 int n,l,r,q[N];
    29 LL p[N],x[N],c[N],f[N],b[N],sp[N];
    30 inline double slop(int k,int j){
    31     return double(f[j]-f[k]+b[j]-b[k])/double(sp[j]-sp[k]);
    32 }
    33 int main(){
    34     int n=getint();
    35     F(i,1,n){
    36         x[i]=getint(); p[i]=getint(); c[i]=getint();
    37         sp[i]=sp[i-1]+p[i]; b[i]=b[i-1]+p[i]*x[i];
    38     }
    39     F(i,1,n){
    40         while(l<r && slop(q[l],q[l+1])<x[i]) l++;
    41         int t=q[l];
    42         f[i]=f[t]-b[i]+b[t]+(sp[i]-sp[t])*x[i]+c[i];
    43         while(l<r && slop(q[r-1],q[r])>slop(q[r],i))r--;
    44         q[++r]=i;
    45     }
    46     printf("%lld
    ",f[n]);
    47     return 0;
    48 }
    View Code
  • 相关阅读:
    perl 获取铜板街页码
    $response->decoded_content 和$response->content
    基于Netty5.0高级案例之请求响应同步通信
    [Err] 1091
    [Err] 23000
    [Err] 42000
    perl 爬取 find_by_tag_name
    perl 爬取html findvalues 方法
    perl 安装DBI和DBD
    js setTimeout 参数传递使用介绍
  • 原文地址:https://www.cnblogs.com/Tunix/p/4331099.html
Copyright © 2020-2023  润新知