玩具装箱 BZOJ 1010
玩具装箱
【问题描述】
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。但他希望费用最小.
【输入格式】
第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7
【输出格式】
输出最小费用
【样例输入】
5 4
3
4
2
1
4
【样例输出】
1
题解:
设f[i]为选完前i个最小的费用
那么转移方程:
发现具有决策单调性
那么······
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<cmath> 7 #define big long long 8 using namespace std; 9 struct Ti 10 { 11 int x, y, z; 12 }o[1000001]; 13 int n, m; 14 big s; 15 big sum[1000001], f[1000001]; 16 big sqr(big x) 17 { 18 return x * x; 19 } 20 big Cal(big x, big y) 21 { 22 return f[x] + sqr(sum[y] - sum[x] + y - x - 1 - m); 23 } 24 int Two(int x, int y, int z, int ss) 25 { 26 int l = x, r = y, mi; 27 while(l <= r) 28 { 29 mi = (l + r) >> 1; 30 if(Cal(ss, mi) < Cal(z, mi)) r = mi - 1; 31 else l = mi + 1; 32 } 33 return l; 34 } 35 int main() 36 { 37 scanf("%d%d", &n , &m); 38 for(int i = 1; i <= n; ++i) 39 { 40 scanf("%lld", &s); 41 sum[i] = sum[i - 1] + s; 42 } 43 int t = 1, w = 1, cc; 44 o[1] = (Ti) {0, n, 0}; 45 for(int i = 1; i <= n; ++i) 46 { 47 if(i > o[t].y) ++t; 48 f[i] = Cal(o[t].z, i); 49 if(Cal(i, n) < Cal(o[w].z, n)) 50 { 51 while(t <= w && Cal(i, o[w].x) < Cal(o[w].z, o[w].x)) --w; 52 if(t <= w) 53 { 54 cc = Two(o[w].x, o[w].y, o[w].z, i); 55 o[w].y = cc - 1; 56 o[++w] = (Ti) {cc, n, i}; 57 } 58 else o[++w] = (Ti) {i, n, i}; 59 } 60 } 61 printf("%lld", f[n]); 62 }