• [HNOI2008]玩具装箱TOY --- DP + 斜率优化 / 决策单调性


    [HNOI2008]玩具装箱TOY

    题目描述:

    P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。

    他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。

    P教授有编号为(1......N)的(N)件玩具,第(i)件玩具经过压缩后变成一维长度为(C_{i}).

    为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。

    同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,

    形式地说如果将第(i)件玩具到第(j)个玩具放到一个容器中,那么容器的长度将为 (x= j - i + sum_{k=i}^{j} C_{k})

    制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为(x),其制作费用为((x - L) ^ {2}).

    其中(L)是一个常量。

    P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过(L)。但他希望费用最小.

    输入格式:

    第一行输入两个整数(N,L).

    接下来(N)行输入(C_{i}).

    (1<=N<=50000, 1<=L,C_{i}<=10^{7})

     

    输出格式:

    输出最小费用

     

    不难想到,(dp(i))表示把(1......i)号玩具装箱的最小费用。

    那么有(dp(i)=min(dp(j)+(sum_{k=j}^{i} C_{k} + i - j - L - 1)^{2}))

    这个(O(n^{2}))的DP一定会超时,因此想办法优化。

    决策单调性:

    如果把决策点打出来,(用(O(n^2))的DP来记录)

    可以观察到满足决策单调性

    而这个东西非常的套路。

    维护一个(tra)指针,表示循环枚举的(i)从哪里转移,(tra)指针要及时更新

    更新出(dp(i))后,用(dp(i))去决定(i)的决策区间在哪里

    第一步:如果栈顶的决策点不如(i),把栈顶决策点退栈,重复直到不满足条件。

    (注:细节:当决策点区间右端点比(i)还小时,同样要退出循环,并且此时(i)的右边全部是它的决策区间,不需要后面的二分了)

    第二步:在当前栈顶决策区间中二分,二分出哪些区间的决策点应该更换为(i)

     

    时间复杂度:(O(n log n))

    不用化式子,只要打表就好了,这么好的算法,为什么不用用??

    代码在此

    斜率优化:

    (dp(i)=min(dp(j)+(sum_{k=j}^{i} C_{k} + i - j - L - 1)^{2}))

    不妨设 (pre(i)=sum_{j=1}^{i} C_{j} +i)

    为了方便,默认(L++)

    那么

    (dp(i)=dp(j)+(pre(i)-pre(j)-L)^{2})

    (dp(i)=dp(j)+pre(i)^{2}+pre(j)^{2}+L^{2}-2*pre(i)*pre(j)-2*pre(i)*L+2*pre(j)*L)

    (dp(j)-pre(j)^{2}-2*pre(j)*L= -2*pre(i)*pre(j) - dp(i) - 2*pre(i)*L+pre(i)^{2}+L*L)

    那么现在就是一个形如(y=kx+b)的式子了

    其中( -2 * pre(i) )为( k ),单调递减

    其中(pre(j))为( x ),单调递增

    同时,要使(dp(i))最小,就要使(b)最大

    所以我们要维护一个上凸壳。

    因为(k,x)同时单调递增,可以选择单调队列

    复杂度:(O(n))

    代码在此

  • 相关阅读:
    201521123098 《Java程序设计》 第5周学习总结
    201521123098 《Java程序设计》 第4周学习总结
    201521123098 《Java程序设计》第3周学习总结
    Beta阶段Scrum 冲刺博客合集
    项目复审——Alpha阶段
    事后诸葛亮分析
    展示博客
    测试与发布
    Alpha阶段敏捷冲刺总结
    敏捷冲刺七
  • 原文地址:https://www.cnblogs.com/reverymoon/p/8905518.html
Copyright © 2020-2023  润新知