终于把最后一道优化DP的题目做了,斜率优化之前掌握的不是非常熟练呀。
朴素方程:f[i]=min{f[k]+s[i]-s[k]-a[k+1]*(i-k)}。
就这么一个朴素方程的化简,搞了很久。
把减号写成加号导致化简完全错误,纠结于直接用double还是用int64的x和y,后来有纠结于≤和≥的问题。这才完全搞定斜率优化。不错的题目。
代码:
var q,f,s,a:array[0..500002] of int64; head,tail,n,m,i,j,t:longint; k,xx,yy,zz:int64; function y(k,j:longint):int64; begin exit(f[k]-f[j]+s[j]-s[k]-a[j+1]*j+a[k+1]*k); end; function x(k,j:longint):int64; begin exit(a[k+1]-a[j+1]); end; begin readln(t); while t>0 do begin dec(t); readln(n,m); for i:=1 to n do begin read(a[i]); s[i]:=s[i-1]+a[i]; end; f[0]:=0; head:=0; tail:=0; q[0]:=0; for i:=1 to n do begin while (head<tail)and(y(q[head],q[head+1])>=i*x(q[head],q[head+1])) do inc(head); k:=q[head]; f[i]:=f[k]+s[i]-s[k]-a[k+1]*(i-k); if i>=2*m-1 then begin zz:=i-m+1; while head<tail do begin xx:=q[tail-1]; yy:=q[tail]; if y(xx,yy)*x(yy,zz)>=(y(yy,zz)*x(xx,yy)) then dec(tail) else break; end; inc(tail); q[tail]:=zz; end; end; writeln(f[n]); end; end.