烽火传递
描述 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] 中的最小值。
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.