烽火传递

    xiaoxiao2021-04-15  85

    题目Problem

    [NOIP2010初赛]烽火传递

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

    输入数据


    5 3 1 2 5 6 2

    输出数据


    4

    备注Hint

    1<=n,m<=1,000,000   这题在整理动态规划题的时候遇到了

    看了原题,发现数据范围根本不是动态规划hold住的,最终优化为单调队列

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

    单调队列

    需要注意

    1.队列中存储的不是元素本身,而是输入的序号

    2.队列要保持单调递增,只有这样,才能保证队列中每个元素都有成为最小元素的可能

     

    #include<iostream> using namespace std; #define MAXN 1000010 int n,m,l,r,a[MAXN],f[MAXN],q[MAXN<<1]; int main(){ cin>>n>>m; for(int i=1;i<=n;i++)cin>>a[i]; l=r=0; for(int i=1;i<=n;i++){ while(l<r&&i-q[l]>m)l++;//队列不为空且队首元素不合法 f[i]=f[q[l]]+a[i];//用队首更新答案 while(l<r&&f[q[r]]>f[i])r--;//更新队尾,使队列保持单调性 q[++r]=i;//进队 } int ans=0x7fffffff; for(int i=n-m+1;i<=n;i++)ans=min(ans,f[i]); cout<<ans; return 0; }

     

     

     

     

     
    转载请注明原文地址: https://ju.6miu.com/read-671963.html

    最新回复(0)