解题报告 telewire

Telewire

 最近,约翰的奶牛们越来越不满足于牛棚里一塌糊涂的电话服务,于是,她们要求约翰把那些老旧的电话线换成性能更好的新电话线。新的电话线架设在已有的n根电话线杆上,第i根电话线的高度为hi,(1=<hi<=100)。电话线总是从一根电话线杆的顶端被引到相邻的那根的顶端,如果这两根电话线杆的高度hi和hj不同,那么约翰就必须支付c*abs(hi-hj)的费用,当然,你不能移动电话线杆,只能按照原有的顺序在相邻杆间架设电话线。

  加高某些电话线杆能减少架设电话线的总费用,尽管这项工作也需要支付一定的费用。更准确的说,如果他把一根电话线杆加高x米的话,他需要付出x^2费用。

 请你帮约翰计算一下,如果合理的进行这两项工作,他最少要在这个电话线改造工程中花多少钱。

输入说明

  第一行输入两个数n和c,含义如上

接下来n行,每行一个整数hi

输出说明

  输出约翰完成电话线改造工程需要花费的最小费用

输入样例

5 2

2

3

5

1

4

输出样例

15

数据范围

N<=100000

C<=100;

Hi<=100;

 

 

 

一个易得的方程是f[i,j]表示第i个电线杆长度为j时的最小费用

f[i,j]:=min(f[i-1,k]+sqr(a[i]-j)+abs(j-k)*c);

观察方程可以转化为等价方程组

if j<=k 那么 f[i,j]:=min(f[i-1,k]+k*c)+sqr(a[i]-j)-j*c

if j>k    那么 f[i,j]:=min(f[i-1,k]-k*c)+sqr(a[i]-j)+j*c

min(f[i-1,k]+k*c)min(f[i-1,k]-k*c)是可以用滚动数组来搞定的

具体实现是这样:用 low[j] 表示min(f[i-1,k]-k*c), high[j] 表示 min(f[i-1,k]+k*c) 。(k<=j) 然后可以预处理出 i=1 时的 low[] 和 high[] ,然后更新 f[i,j] 的时候,顺便更新一下对应的 low[] high[] 也就是滚动数组。

然后,代码 ???

program telewire;

 

const

  maxn=100001;

  maxint=99999999;

 

var

  f:array[-1..maxn,-1..101] of longint;

  high,low:array[-1..100] of longint;

  a:array[-1..maxn] of longint;

  n,c,up,down,i,j,k,ans:longint;

 

function min(a,b:longint):longint;

begin

  if a<b then exit(a) else exit(b);

end;

 

begin

  readln(n,c);

  up:=0;

  down:=101;

  for i:=1 to n do

    begin

      readln(a[i]);

      if a[i]>up then up:=a[i];

      if a[i]<down then down:=a[i];

    end;

 

  filldword(f,sizeof(f)>>2,maxlongint>>2); 

 

  for i:=a[1] to 100 do

    f[1,i]:=(a[1]-i)*(a[1]-i);

 

  fillchar(low,sizeof(low),63);

  low[up]:=f[1,up]+up*c;

  for k:=up-1 downto down do

     low[k]:=min(low[k+1],f[1,k]+k*c);

 

  fillchar(high,sizeof(high),63);

  high[down]:=f[i,down]-down*c;

  for k:=down+1 to up do

     high[k]:=min(high[k-1],f[1,k]-k*c);

 

  for i:=2 to n do

    begin

      for j:=a[i] to up do

        begin

          f[i,j]:=min(f[i,j],low[j]+(a[i]-j)*(a[i]-j)-j*c);

          f[i,j]:=min(f[i,j],high[j]+(a[i]-j)*(a[i]-j)+j*c);

        end;

 

      fillchar(low,sizeof(low),63);

      low[up]:=f[i,up]+up*c;

      for k:=up-1 downto down do

        low[k]:=min(low[k+1],f[i,k]+k*c);

 

      fillchar(high,sizeof(high),63);

      high[down]:=f[i,down]-down*c;

      for k:=down+1 to up do

        high[k]:=min(high[k-1],f[i,k]-k*c);

    end;

 

  ans:=maxlongint;

 

  for i:=down to up do

    if ans>f[n,i] then ans:=f[n,i];

 

  writeln(ans);

end.

 

 

 

 

原文地址:https://www.cnblogs.com/SueMiller/p/2232038.html