您的位置:首页 > 其它

1010: [HNOI2008]玩具装箱toy

2015-12-13 11:57 309 查看

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<i

如果取k时的方案比j优

[b]f[j] + x[i]^2 - 2*t[j]*x[i] + t[j]^2 > [b]f[k] + x[i]^2 - 2*t[k]*x[i] + t[k]^2
[/b][/b]
[b][b]略加整理得[/b][/b]
[b](f[j] + t[j]^2 - f[k] - t[k]^2) / (t[j] - t[k]) < 2*x[i][/b]
[b]//由于t数组肯定是单调递增的,所以除过来不等式要变号。。[/b]
[b][b]这样不等式左边就是一个斜率一样的东西[/b][/b]
[b][b]另j,k的斜率为g[j,k][/b][/b]
[b][b]若当前有a<b<c[/b][/b]
[b][b]设g[a,b] > g[b,c][/b][/b]
[b][/b]
[b][b]i:[/b][/b]
[b]g[b,c] < 2*x[i][/b]
[b]则c比b优[/b]
[b][/b]
[b][b]ii:[/b][/b]
[b]g[b,c] > 2*x[i] [/b]
则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<iostream>
#include<cstdio>
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
;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: