1010: [HNOI2008]玩具装箱toy

1010: [HNOI2008]玩具装箱toy

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 7763   Solved: 2981
[ Submit][ Status][ Discuss]

Description

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

Input

第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

Output

输出最小费用

Sample Input

5 4
3
4
2
1
4

Sample Output

1

HINT




斜率优化dp。。。
名字听起来就很屌有木有!!!!!

暴力:
f[i] = min(f[j] + (sum[i]-sum[j]+i-j-1-L)^2)

显然肯定超时呀。。

设t[i] = sum[i] + i;x[i] = t[i] - 1 - L
于是原式等价于
f[j] + x[i]^2 - 2*t[j]*x[i] + t[j]^2;

不妨设 j

如果取k时的方案比j优
f[j] + x[i]^2 - 2*t[j]*x[i] + t[j]^2 > f[k] + x[i]^2 - 2*t[k]*x[i] + t[k]^2
略加整理得
(f[j] + t[j]^2 - f[k] - t[k]^2) / (t[j] - t[k]) < 2*x[i]
//由于t数组肯定是单调递增的,所以除过来不等式要变号。。
这样不等式左边就是一个斜率一样的东西
另j,k的斜率为g[j,k]
若当前有a
设g[a,b] > g[b,c]

i:
g[b,c] < 2*x[i]
则c比b优

ii:
g[b,c] > 2*x[i] 
则b比c优
但是同时g[a,b] > g[b,c] > 2*x[i]
于是a比b优

于是上面情况发生时可舍去b
所以考虑的任意斜率必须满足单调递增

假设维护一个单调递增的斜率队列
则可找到一中间点使其左边所有斜率 <= 2*x[i] 右边所有斜率>= 2*x[i]
显然此时改点最优
对于该点左边的,既然当前斜率<=2*x[i]而x[i]是单调递增的
所以这些点永远比自己右边的那个点差,所以舍去它们

这样就可得到O(N)复杂度的算法!

#include
#include
using namespace std;
 
const int maxn = 50050;
typedef long long LL;
typedef double DB;
 
LL sum[maxn],x[maxn],t[maxn],n,i,j,f[maxn],L;
int q[maxn],head,tail = -1;
 
LL getnum()
{
    char ch; LL ret = 0;
    ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') {
        ret = ret*10 + ch - '0';
        ch = getchar();
    }
    return ret;
}
 
DB slope(int a,int b)
{
    return (DB)(f[a] + t[a]*t[a] - f[b] - t[b]*t[b]) / (DB)(t[a] - t[b]);
}
 
int main()
{
    #ifdef YZY
        freopen("yzy.txt","r",stdin);
    #endif
     
    n = getnum(); L = getnum();
    sum[0] = f[0] = 0;
    for (i = 1; i <= n; i++) {
        sum[i] = getnum();
        sum[i] += sum[i-1];
        t[i] = sum[i] + i;
        x[i] = t[i] - 1 - L;
    }
     
    q[++tail] = 0;
    for (i = 1; i <= n; i++) {
        if (tail <= head) {
            q[++tail] = i;
            j = q[head];
            f[i] = f[j] + x[i]*x[i] - 2*x[i]*t[j] + t[j]*t[j];
            continue;
        }
        while (tail > head && slope(q[head],q[head+1]) <= 2*x[i]) ++head;
        j = q[head];
        f[i] = f[j] + x[i]*x[i] - 2*x[i]*t[j] + t[j]*t[j];
        while (tail - head >= 1 && slope(q[tail-1],q[tail]) >= slope(q[tail],i)) tail--;
        q[++tail] = i;
    }
    cout << f[n];
    return 0;
}


你可能感兴趣的:(dp)