烽火传递


描述 Description

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

输入格式 InputFormat
第一行有两个数n,m分别表示n个烽火台,在m个烽火台中至少要有
一个发出信号。
第二行为n个数,表示每一个烽火台的代价。

输出格式 OutputFormat
一个数,即最小代价。

样例输入 SampleInput
5 3
1 2 5 6 2

样例输出 SampleOutput
4

数据范围和注释 Hint
1<=n,m<=1,000,000

时间限制 TimeLimitation
各个测试点1s

解题报告
搜到的单调队列方法的题解只有代码……于是把代码扒下来看了n遍终于搞懂了。
单调队列优化dp,记f[i]为第i位必选时所能达到的最小代价,所以可以写出方程 f[i]=min(f[j])+a[i],j=i-m..i-1 。
单调队列维护f的值,以保证每次取min(f[j])为O(1)的复杂度。
目标状态为 f[n-m+1]..f[m] 中的最小值。

代码

View Code
 1 var
 2     a,q,f:array[1..1000001]of longint;
 3     m,n,i,h,t,ans:longint;
 4 begin
 5     read(m,n);
 6     for i:=1 to n do read(a[i]);
 7     t:=0;
 8     h:=1;
 9     ans:=1000000001;
10     for i:=1 to n do begin
11         while ((i-m)>q[h])and(h<=t) do inc(h);
12         while (f[i-1]<f[q[t]])and(t>=h) do dec
13 
14 (t);
15         inc(t);
16         q[t]:=i-1;
17         f[i]:=a[i]+f[q[h]];
18     end;
19     for i:=n-m+1 to n do if ans>f[i] then ans:=f[i];
20     writeln(ans);
21 end.
posted @ 2012-10-28 11:28  wangziyun  阅读(741)  评论(0编辑  收藏  举报
神奇的东西