2018.09.06 烽火传递(单调队列优化dp)

描述

烽火台是重要的军事防御设施,一般建在交通要道或险要处。一旦有军情发生,则白天用浓烟,晚上有火光传递军情。

在某两个城市之间有 n 座烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确传递,在连续 m 个烽火台中至少要有一个发出信号。现在输入 n,m 和每个烽火台的代价,请计算总共最少的代价在两城市之间来准确传递情报。

输入

第一行是 n,m ,表示 n 个烽火台和连续烽火台数 m ;

第二行 n 个整数表示每个烽火台的代价 ai

输出

输出仅一个整数,表示最小代价。

样例输入

5 3

1 2 5 6 2

样例输出

4

提示

在第 2,5 号烽火台上发信号。

对于全部数据,1≤n,m≤2×105,1≤ai≤1000

标签

NOIP2010提高组初赛 · 完善程序


好像就是一个挺裸的单调队列优化dp,f[i]表示i这个位置选的最优值。

于是f[i]的答案可以从f[i−m]" role="presentation" style="position: relative;">f[i−m]f[i−m]~f[i−1]" role="presentation" style="position: relative;">f[i−1]f[i−1]转移过来,显然只用维护这些值的最小值就行了。

这不就是单调队列优化dp干的事情吗?

代码:

#include<bits/stdc++.h>
#define N 200005
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
int n,m,a[N],f[N],hd,tl,q[N];
int main(){
    n=read(),m=read(),hd=1,tl=1;
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i){
        while(hd<tl&&q[hd]+m<i)++hd;
        f[i]=f[q[hd]]+a[i];
        while(hd<tl&&f[q[tl]]>f[i])--tl;
        q[++tl]=i;
    }
    int ans=0x3f3f3f3f;
    for(int i=n-m+1;i<=n;++i)ans=min(ans,f[i]);
    cout<<ans;
    return 0;
}
上一篇:pythonweb服务器编程(一)


下一篇:TYVJ 1305 最大子序和 ++ 烽火传递