SSL_2883 烽火传递 【单调性】
Description
烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在某两座城市之间有n个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续 m 个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。
Input
第一行:两个整数 N,M。其中N表示烽火台的个数, M 表示在连续 m 个烽火台中至少要有一个发出信号。接下来 N 行,每行一个数 Wi,表示第i个烽火台发出信号所需代价。
Output
一行,表示答案。
Sample Input
5 3
1
2
5
6
2
Sample Output
4
Hint
对于50%的数据,M≤N≤1,000 。 对于100%的数据,M≤N≤100,000,Wi≤100。
这道题单纯用动归显然会超时,要用单调队列来优化。具体请看代码注释。
#include<iostream>
#include<cstdio>
#define maxx 200000
using namespace std;
int f[maxx],q[maxx],a[maxx],n,m,h,t;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
while(h<=t and f[i-1]<f[q[t]]) t--; //当f[i-1]比队列尾部更优,就用f[i-1]替换掉队尾
q[++t]=i-1; //存储队列中元素的下标
while(h<=t and q[h]<i-m) h++; //如果队列元素离开维护范围,出队
f[i]=f[q[h]]+a[i]; //状态转移
}
int ans=0x7fffffff;
for(int i=n-m+1;i<=n;i++){
/*
ans=min(ans,f[i]); 在最后的m个元素中找到最小的
} */
cout<<ans;
return 0;
}