烽火传递

题目

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

样例输出:
一行,表示答案。
4

数据范围:
对于50%的数据,M≤N≤1,000 。
对于100%的数据,M≤N≤ 100,000,Wi≤100
————————–剖解题目————————
给你一段序列,要求每一个长度为m的区间内都必须取一个数,求这些数的和最小。


思路:求最优值,综合考虑决策性与后效性,考虑dp
————–解法—————
DP:设f[i]表示点燃当前位置烽火台,且前i个满足要求的最小代价。
显然就有f[i]=min(f[j])+a[i](i-m<=j<=i-1)。
当然,这会超时,所以要有优化。
优化一:肯定是从前m个里选小的,涉及到区间最小值,可用线段树,时间复杂度将为O(n log m)。
优化二:同样因为要选前m个最小的,使用单调队列,队列里存有不超过m个长度单位的值,每次取队首,进队时维护队列使其单调不下降,复杂度将为O(n)。


代码(pascal+优化二)

uses math;
const maxn=100005;
var
        n,m,i,j,h,t,x:longint;
        f:array[0..maxn]of longint;
        fre:array[0..maxn]of record
                val,pos:longint;
        end;
begin
        readln(n,m);
        t:=0; h:=1;
        for i:=1 to m do
        begin
                readln(x);
                f[i]:=x;
                while (xval)and(t>0) do dec(t);
                inc(t);
                fre[t].val:=x;
                fre[t].pos:=i;
        end;
        for i:=m+1 to n do
        begin
                readln(x);
                while (fre[h].posand(hdo inc(h);
                f[i]:=fre[h].val+x;
                while (f[i]val)and(t>0) do dec(t);
                inc(t);
                fre[t].val:=f[i];
                fre[t].pos:=i;
        end;
        j:=maxlongint;
        for i:=n-m+1 to n do j:=min(j,f[i]);
        writeln(j);
end.

烽火传递_第1张图片

你可能感兴趣的:(信息技术,线段树,动态规划,单调队列)