HNOI2008玩具装箱toy例题

HNOI2008玩具装箱toy题解
  • 题目描述 Description
    P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为x=ji+Sigmajk=i(Ck) 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(xL)2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.

  • 输入描述 Input Description
    第一行输入两个整数N,L.接下来N行输入Ci,1N50000,1L,Ci107

  • 输出描述 Output Description
    输出最小费用

  • 样例输入 Sample Input
    5 4
    3
    4
    2
    1
    4

  • 样例输出 Sample Output
    1

  • 题解
    首先推荐一篇文章《1D1D动态规划优化初步》,上面详细地介绍了单调栈优化的方法。
    f[i]表示前i件玩具放入容器内的最小代价,通过一些简单的分析,我们可以得到这样一个DP方程:
    f[i]=mini1j=0{f[j]+w(j+1,i)},(f[0]=0)
    其中w(x,y)=(yx+Sigmayi=x(Ci)L)2
    我们把C数组处理成前缀和,那么w(x,y)可在O(1)的时间内算出,直接求解的话整个方程的时间复杂度是O(n2)
    设当f[i]取到最优值时f[i]=f[k]+w(k+1,i),则记f[i]由决策k转移过来。//那么i=1时应有k=0
    可以证明(也可以打出决策表来观察)这个方程中k的值是单调不降的。所以可以套用单调栈优化,时间复杂度O(nlog2n)通过本题。
    注意开longlong,不要unsigned。

  • Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 50010;
ll f[maxn], c[maxn];
int n, L, top;
struct stack          //决策栈
{
    int k, s, t;
    stack(int k = 0, int s = 0, int t = 0) :k(k), s(s), t(t) {}
} S[maxn];
void init()
{
    scanf("%d%d", &n, &L);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%lld", &c[i]);
        c[i] += c[i - 1];
    }
}
inline ll w(int x, int y)
{
    return (y - x + c[y] - c[x - 1] - L) * (y - x + c[y] - c[x - 1] - L);
}
void work()
{
    f[0] = 0;
    S[++top] = stack(0, 0, n);
    for(int i = 1; i <= n; ++i)
    {
        int lft = 1, rit = top, mid;
        while(lft <= rit)            //计算f[i]
        {
            mid = ((lft + rit) >> 1);
            if(S[mid].s <= i && S[mid].t >= i)
            {
                f[i] = f[S[mid].k] + w(S[mid].k + 1, i);
                break;
            }
            if(i < S[mid].s) rit = mid - 1;
            else lft = mid + 1;
        }
        while(top > 0)              //更新决策栈
        {
            if(f[S[top].k] + w(S[top].k + 1, S[top].s) < f[i] + w(i + 1, S[top].s))
            {
                lft = S[top].s; rit = S[top].t;
                while(lft <= rit)
                {
                    mid = ((lft + rit) >> 1);
                    if(f[S[top].k] + w(S[top].k + 1, mid) < f[i] + w(i + 1, mid)) lft = mid + 1;
                    else rit = mid - 1;
                }
                S[top].t = rit;
                break;
            }
            --top;
        }
        if(lft <= n) S[++top] = stack(i, lft, n);
    }
    printf("%lld", f[n]);
}
int main()
{
    init();
    work();
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。