hdu 3507 Print Article 斜率优化dp

来源:互联网 发布:淘宝上传视频怎么传 编辑:程序博客网 时间:2024/05/18 03:39

题意:给你一列数,要你把这列数分成若干段,每一段的权值为sigma(c[i])^2+m,求最小的总权值。


分析:很容易得到方程f[i]=min(f[j]+(s[i]-s[j])^2+m){j<i}

但数据要求是n<=500000,很显然会T,所以这时候就要用到斜率优化。

假设i>j>k,且对于i来说j比k优,那么可以得到f[j]+(s[i]-s[j])^2+m<f[k]+(s[i]-s[k])^2+m

化简一下可得(f[j]-f[k]+s[j]^2-s[k]^2)/(2*s[j]-2*s[k])<s[i]

也就是说若满足该条件则对于i而言j比k优

设g[j,k]=(f[j]-f[k]+s[j]^2-s[k]^2)/(2*s[j]-2*s[k])

同时还可以得到一个很重要的结论,就是若g[i,j]<=g[j,k]则j一定不会成为最优解从而可以删去。

证明:若g[j,k]>=s[i]则k比j优;若g[j,k]<s[i]则必有g[i,j]<s[i],那么可以得出i比j优。

那么我们可以建一个优先队列来维护,那么每次队首的一定是最i而言最优的,每处理好一个f[i]后就把i放入队列并把没i优的元素删去。

那么时间复杂度就由O(n^2)变成了O(n)


注意要开int64!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


代码:

var  q:array[0..500005] of longint;  f,s:array[0..500005] of int64;  n,m:longint;procedure init;var  i,x:longint;begin  readln(n,m);  for i:=1 to n do  begin    readln(x);    s[i]:=s[i-1]+x;  end;end;function getup(j,k:longint):int64;begin  getup:=f[j]-f[k]+s[j]*s[j]-s[k]*s[k];end;function getdown(j,k:longint):int64;begin  getdown:=2*s[j]-2*s[k];end;procedure main;var  head,tail,i,x,y,z:longint;begin  head:=1;  tail:=1;  q[1]:=0;  for i:=1 to n do  begin    while head<tail do    begin      x:=q[head+1]; y:=q[head];      if getup(x,y)<=s[i]*getdown(x,y)        then inc(head)        else break;    end;    x:=q[head];    f[i]:=f[x]+m+sqr(s[i]-s[x]);    while head<tail do    begin      x:=i; y:=q[tail]; z:=q[tail-1];      if getup(x,y)*getdown(y,z)<=getup(y,z)*getdown(x,y)        then dec(tail)        else break;    end;    inc(tail);    q[tail]:=i;  end;  writeln(f[n]);end;begin  while not eof do  begin    init;    main;  end;end.


1 0
原创粉丝点击