HDU3507 BZOJ1010 DP决策单调优化 pascal

本文介绍了一种通过利用决策单调性将动态规划的时间复杂度从O(N^2)优化到O(NlogN)的方法,并提供了两个具体的实现案例。
这两题都是某一个很神的一个论文里(留邮箱。。我发)写的第一种模型

F[I]:=MIN{F[J]+W[J+1,I]}(1<=J<I)中的

我们可以打表观察决策然后来确定满不满足决策单调性。

决策单调性就是:假设G[I]为i的决策位置

那么G[I]<=G[J](i<j)一定满足

所以可以把O(N^2)的DP优化到O(NLOGN)

code:(注意 continue)

BZOJ 1010

var
  l,r,c:array[0..50005] of longint;
  a,sum,f:array[0..50005] of int64;
  t1,m:int64;
  i,n,h,t,head,tail,mid:longint;
function work(i,j,k:longint):boolean;
  var
    t1,t2:int64;
  begin
    t1:=(sum[i]-sum[j]-m+(i-j-1))*(sum[i]-sum[j]-m+(i-j-1))+f[j];
    t2:=(sum[i]-sum[k]-m+(i-k-1))*(sum[i]-sum[k]-m+(i-k-1))+f[k];
    if t1<t2 then exit(false) else exit(true);
  end;
begin
  fillchar(f,sizeof(f),0);
  fillchar(sum,sizeof(sum),0);
  read(n,m);
  for i:=1 to n do
    begin
      read(a[i]);
      sum[i]:=sum[i-1]+a[i];
    end;
  h:=1;t:=1;l[h]:=1;r[h]:=n;c[h]:=0;  
  for i:=1 to n do
    begin
      while r[h]<i do
        h:=h+1;
      t1:=sum[i]-sum[c[h]]+(i-c[h]-1)-m;
      t1:=t1*t1;
      f[i]:=f[c[h]]+t1;
      while work(l[t],c[t],i) and (h<t) do
        begin
          t:=t-1;
          r[t]:=r[t+1];     
        end;
      if work(l[t],c[t],i) and (h=t) then
        begin
          c[h]:=i;
          continue;
        end;
      head:=l[t];tail:=r[t];
      if head<=i then head:=i+1;
      while head<=tail do
        begin
          mid:=(head+tail) div 2;
          if work(mid,c[t],i) then tail:=mid-1 else head:=mid+1;
        end;
      tail:=tail+1;
      t:=t+1;
      R[T-1]:=tail-1;
      l[t]:=tail;r[t]:=n;c[t]:=i;
    end;
  writeln(f[n]);
end.
          
    

HDU 3507


var
  n,i,h,t,head,tail,mid:longint;
  f,a,sum:array[0..500005] of int64;
  l,r,c:array[0..500005] of longint;
  m,tmp,t1:int64;
function work(i,j,k:longint):boolean;
  var
    t1,t2:int64;
  begin
    t1:=(sum[i]-sum[j])*(sum[i]-sum[j])+f[j]+m;
    t2:=(sum[i]-sum[k])*(sum[i]-sum[k])+f[k]+m;
    if t2<=t1 then work:=true else work:=false;
  end;
begin
  assign(input,'1.in');assign(output,'1.ans');
  reset(input);rewrite(output);
  while not eof do begin
    fillchar(f,sizeof(f),0);
    fillchar(sum,sizeof(sum),0);
  readln(n,m);
  for i:=1 to n do
    begin 
      readln(a[i]);
      sum[i]:=sum[i-1]+a[i];
    end;
  h:=1;t:=1;
  l[h]:=1;r[h]:=n;c[h]:=0;
  for i:=1 to n do
    begin
      while r[h]<i do
        h:=h+1;
      t1:=(sum[i]-sum[c[h]]);
      tmp:=t1*t1+m;
      f[i]:=f[c[h]]+tmp;
      while work(l[t],c[t],i) and (t>h) do
        begin
          t:=t-1;
          r[t]:=r[t+1];
        end;
      if work(i+1,c[t],i) and (t=h) then 
        begin
          c[t]:=i;
          continue;
        end;
      head:=l[t];tail:=r[t];
      if head<=i then head:=i+1;
      while head<=tail do
        begin
          mid:=(head+tail) div 2;
          if work(mid,c[t],i) then tail:=mid-1 else head:=mid+1;
        end;
      tail:=tail+1;
      t:=t+1;
      r[t-1]:=tail-1;
      l[t]:=tail;r[t]:=n;c[t]:=i;
    end;
  writeln(f[n]);end;close(input);close(output);
end.


评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值