SSLOJ 2883 烽火传递

题目

   

Description

 

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

 

Input

 

第一行:两个整数 NM。其中N表示烽火台的个数, M 表示在连续 m 个烽火台中至少要有一个发出信号。接下来 N 行,每行一个数 Wi,表示第i个烽火台发出信号所需代价。

 

Output

 

一行,表示答案。

 

  5 3

  1 2 5 6 2

 

  4   

Data Constraint

 

对于50%的数据,M≤N≤1,000 。 对于100%的数据,

 

M≤N≤100,000Wi≤100

 

分析

    这道很明显,如果用DP做一定超时,所以我们用单调队列优化

    那该怎么优化法呢

    首先我们分析状态转移方程  f[j]=min(f[j],f[k]+a[i])

    如果做的是循环k 然后直接枚举.  o(n^2)

    显然这肯定超时

    所以我们就这样做:

    构造一个递增单调队列,所以最小的值一定在队头

    用单调队列来代表f里面的值的

    这样就可以省下k这个循环了

    但是最后的答案是在i=n-m  i<=n 里

代码

 1 #include<iostream>
 2 #define N 100000
 3 using namespace std;
 4 int a[N+1];
 5 int f[N+1],que[N+1];
 6 int main ()
 7 {
 8     int n,m;
 9     cin>>n>>m;
10     for (int i=1;i<=n;i++)
11         cin>>a[i];
12     int h=1,t=1;
13     for (int i=1;i<=n;i++)
14     {
15         while (h<=t&&f[i-1]<=f[que[t]]) t--;   //如果当前插入的值比队尾小就要插队
16         que[++t]=i-1;
17         while (h<=t&&que[h]+m<i) h++;  //如果超出范围就要头指针后移
18         f[i]=f[que[h]]+a[i];   //结果就是当前队列最小值加上当前a了
19     }
20     int ans=1e9;
21     for (int i=n;i>n-m;i--)
22        ans=min(ans,f[i]);
23     cout<<ans;
24 }

 

posted @ 2019-01-05 16:27  Melted_czj  阅读(231)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色