• 烽火传递


    题目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;
    }
     
  • 相关阅读:
    根据模板自动生成数据
    CSV to XLSX (专用)
    释放用完的Excel COM组件
    配置文件的力量
    字符编解码的故事(ASCII,ANSI,Unicode,Utf-8区别)
    将结果中的省略号内容全部输出
    Powershell变量的类型
    一些用过的C#类库收集
    运算符
    特殊运算符
  • 原文地址:https://www.cnblogs.com/thmyl/p/6361177.html
Copyright © 2020-2023  润新知