话说这题很久以前就写过,然后好像一直忘了写题解……
以前看这道题还觉得挺难的,现在觉得好水
首先朴素的想法肯定是动归
f[i,j]表示到处理到第i根电线,最终高度为j的最小花费
f[i,j]:=min(f[i-1,k]+sqr(h[i]-j)+abs(j-k)*c) (h[i]<=j<=max) max为原来所有电线最高的高度
但这个会超时,我们就要想办法优化;
考虑这样一个方程式f[i,j]:=min(f[i-1,k]+sqr(h[i]-j)+(j-k)*c);
我们很容易用O(max)的时间完成转移(好像之前有过例子);
但这个方程式多了一个绝对值,根据数学上的思想,我们就去绝对值讨论呗;
容易整理得到
f[i,j]=min(min(f[i-1,k]-k*c+j*c) j>=k, min(f[i-1,k]+k*c-j*c) j<=k)+sqr(h[i]-j)
这样不难想到,令
tal[j]=min(f[i-1,k]+k*c) k∈[j,max];
sho[j]=min(f[i-1,k]-k*c) k∈[h[i-1],j]
tal[j]表示上一根电线杆状态高度大于当前电线杆高度j高的花费中的最小值
sho[j]表示上一根电线杆状态高度小于当前电线杆高度j高的花费中的最小值
然后弄弄就出来了
1 const hmax=100; 2 inf=2147483647; 3 var h:array[0..100010] of longint; 4 sho,tal:array[0..1010] of longint; 5 f:array[0..1,0..1010] of longint; 6 i,k1,k2,n,m,j,c,ans:longint; 7 function min(a,b:longint):longint; 8 begin 9 if a>b then exit(b) else exit(a); 10 end; 11 12 begin 13 readln(n,c); 14 for i:=1 to n do 15 begin 16 readln(h[i]); 17 if h[i]>m then m:=h[i]; 18 end; 19 h[n+1]:=h[i]; 20 k1:=1; 21 k2:=0; 22 for i:=h[1] to m do 23 f[0,i]:=sqr(i-h[1]); 24 for i:=2 to n do 25 begin 26 k1:=k1 xor 1; 27 k2:=k2 xor 1; 28 for j:=0 to m do 29 begin 30 tal[j]:=inf; 31 sho[j]:=inf; 32 f[k2,j]:=inf; 33 end; 34 tal[m]:=f[k1,m]+c*m; 35 for j:=m-1 downto h[i-1] do 36 tal[j]:=min(tal[j+1],f[k1,j]+c*j); 37 sho[h[i-1]]:=f[k1,h[i-1]]-c*h[i-1]; 38 for j:=h[i-1]+1 to m do 39 sho[j]:=min(sho[j-1],f[k1,j]-c*j); 40 for j:=h[i] to m do 41 if j<h[i-1] then 42 f[k2,j]:=min(f[k2,j],tal[h[i-1]]-c*j+sqr(j-h[i])) //注意细节,这时候上一根电线杆不存在比这根矮的状态 43 else 44 f[k2,j]:=min(f[k2,j],min(tal[j]-c*j,sho[j]+c*j)+sqr(j-h[i])); 45 end; 46 ans:=inf; 47 for i:=h[n] to m do 48 ans:=min(ans,f[k2,i]); 49 writeln(ans); 50 end.