烽火传递 dp+单调队列

题目大意

    烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在某两座城市之间有n个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续m个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。


分析

    要用动态规划的方法解决。我们可以写出这样的方程f[i]:=min{f[j]}+a[i](i-m<=j<i-1)(因为要保证i之前的3个中必须存在被点亮的烽火台)。

    那问题就变成了在f[i-m]到f[i-1]中找一个最小的。

    单调队列可以很好地完成这个任务。

    单调队列见——单调队列


代码

var
  a:array[0..1000001] of longint;
  d,v:array[0..1000001] of longint;
  f:array[0..1000001] of longint;
  head,tail:longint;
  i,j,k:longint;
  n,m:longint;
  ans:longint;

begin
  readln(n,m);
  for i:=1 to n do
    readln(a[i]);
  fillchar(d,sizeof(d),0);
  fillchar(v,sizeof(v),0);
  head:=1;
  tail:=0;
  for i:=1 to n do
    begin
      while (v[head]<i-m) and (head<=tail) do
        head:=head+1;
      while (f[i-1]<f[v[tail]]) and (head<=tail) do
        tail:=tail-1;
      tail:=tail+1;
      v[tail]:=i-1;
      f[i]:=f[v[head]]+a[i];
    end;
  ans:=maxlongint;
  for i:=n-m+1 to n do
    if ans>f[i] then ans:=f[i];
  write(ans);
end.


posted @ 2016-07-08 07:48  一个响亮的蒟蒻  阅读(198)  评论(0编辑  收藏  举报