bzoj 1010 [HNOI2008]玩具装箱
Bzoj 1010 [hnoi2008]toy
题目大意:给n个数,求将这些数切成数段,每段的长度为(sum+(i-j+1)-l)^2,求总的长度和最小。
裸dp dp[i] := min(dp[k] + (f[i]-f[j]-c) 有 i<j,f[i] = sum[i] + I; c = l+1
把方程转化为 y=kx+ans,ans即我们要求的数,x,y,k通过枚举的j可知,所以在斜率一定的情况下,直线 k?+ans 第一个碰到的决策点即使ans最小。
然后通过斜率优化,可以证明决策点的最优,构建维护一个单调队列(点与点之间的斜率单调递增)(队尾维护),然后队首则维护首2点斜率大于k(k也可以推出随i增加单调的)
{补充:单调队列维护下凸性,队首维护解决当前最优解,队尾维护则是删除上凸点}
Dp[x] = min(dp[i]+(f[x]-f[i]-c)^2)
=f[x]^2+min(dp[i]-2f[x](f[i]+c)+(f[i]+c)^2)
设 dp[x]-f[x]^2=G dp[i]+(f[i]+c)^2 = Ti 2(f[i]+c) = Hi
原式 = G = Ti –f[x]Hi
直线 = Ti = G+f[x]Hi
斜率 = Tj-Ti / Hj-Hi
感谢这两篇文章带领我认识斜率优化
这个分析的很论文很像,托这个的福才顺利理解了原理的
http://hi.baidu.com/ext_newbie/blog/item/98f66c31875426250a55a9de.html
这个跳得有点快,直接上斜率,没有突出点的形式,让我有点费解,但是很简洁,看不懂也是因为神牛对我的bs吧= =
http://blog.sina.com.cn/s/blog_5e6fc6d60100vp2j.html
以及国家队2004论文
一句话:使转移点呈现单调递增函数的模样,然后有一条斜率单调递增的直线与这个函数相切,切点为ans。
1 //bzoj 1010 [hnoi2008] toy 2 const 3 maxn=51111; 4 inf='1.txt'; 5 var 6 dp, f: array[0..maxn]of qword; 7 q: array[0..maxn]of longint; 8 n, l: longint; 9 c: int64; 10 procedure init; 11 var 12 i: longint; 13 begin 14 fillchar(dp, sizeof(dp), 0); 15 fillchar(f, sizeof(f), 0); 16 readln(n, l); 17 for i := 1 to n do begin 18 readln(f[i]); f[i] := f[i] + f[i-1] + 1; 19 end; 20 c := l + 1; 21 end; 22 23 function g(j, i: longint): qword; 24 begin exit(dp[i]+(f[i]+c)*(f[i]+c)-dp[j]-(f[j]+c)*(f[j]+c)); end; 25 26 function s(j, i: longint): qword; 27 begin exit(2*(f[i]-f[j])); end; 28 29 procedure main; 30 var 31 j, head, tail, i, u, x, y, z: longint; 32 begin 33 head := 1; tail := 1; 34 q[tail] := 0; 35 for i := 1 to n do begin 36 while (head<tail)and(g(q[head], q[head+1])<=f[i]*s(q[head], q[head+1])) do inc(head); 37 u := q[head]; 38 dp[i] := dp[u] + (f[i]-f[u]-c)*(f[i]-f[u]-c); 39 inc(tail); q[tail] := i; 40 while (head+2<=tail) do begin 41 x := q[tail-2]; y := q[tail-1]; z := q[tail]; 42 if not(g(x, y)*s(y, z)<g(y, z)*s(x, y)) then begin 43 q[tail-1] := q[tail]; dec(tail); 44 end 45 else break; 46 end; 47 end; 48 49 end; 50 51 procedure print; 52 begin 53 writeln(dp[n]); 54 end; 55 56 begin 57 assign(input,inf); reset(input); 58 init; 59 main; 60 print; 61 end.