[BZOJ3156] 防御准备

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=3156

题目大意

每个点可以建个守卫塔(给定价格),或者向右移动到最近的守卫塔(价格为距离)询问最小价格

题解

dp[i]=min{dp[j]+(ij)(ij1)2+x[i]}
dp[i]=min{dp[j]+j22ij+j2}+i2i+x[i]
j<kk
dp[j]+j22ij+j2>dp[k]+k22ik+k2
dp[j]dp[k]>k22ik+k2j22ij+j2
dp[j]dp[k]k2+kj2j2>i(jk)
jk<0
dp[j]dp[k]k2+kj2j2jk<i

const
 maxn=1000005;
var
 dp,x:array[0..maxn]of int64;
 t:array[0..maxn]of longint;
 i,j,k,n,tt,l,r:longint;
function f(a,b:longint):real;
var c,d,e:real;
begin
 c:=a; d:=b;
 e:=(dp[a]-dp[b]+(c*c+c-d*d-d)/2)/(c-d);
 exit(e);
end;

begin
 readln(n);
 for i:=1 to n do
  read(x[i]);
 l:=1; r:=1; t[1]:=0;
 for i:=1 to n do
  begin
   while (l<r)and(f(t[l],t[l+1])<=i) do inc(l);
   tt:=t[l]; dp[i]:=dp[tt]+x[i]+((i-tt)*(i-tt-1))div 2;
   while (l<r)and(f(t[r-1],t[r])>f(t[r],i)) do dec(r);
   inc(r); t[r]:=i;
  end;
 writeln(dp[n]);

 {fillchar(dp,sizeof(dp),0);
 for i:=1 to n do
  begin
   dp[i]:=maxlongint;
   for j:=0 to i-1 do
    if dp[j]+x[i]+((i-j)*(i-j-1))div 2<dp[i]
    then begin tt:=j; dp[i]:=dp[j]+x[i]+((i-j)*(i-j-1))div 2; end;
   writeln(i,' ',dp[i],' ',tt);
  end;
 writeln(dp[n]);}

end.

你可能感兴趣的:([BZOJ3156] 防御准备)