题目描述

烽火台是重要的军事防御设施,一般建在交通要道或。
一旦有军情发生,则白天用浓烟,晚上有火光传递军。
在某两个城市之间有n座烽火台,每个烽火台发出信。
为了使情报准确传递,在连续 m
个烽火台中至少要有一个发出信号。
现在输入 n,m
和每个烽火台的代价,请计算在两城市之间准确传递情报所需花费的总代价最少为多少。

输入样例

5 3
1 2 5 6 2

输出样例

4

算法1

(普通DP)

考虑DP,dp[i][j]表示当前已选至i,其中有j个烽火台没有选.
可得状态转移方程:

f[i]:=min{f[j]}+a[i](i-m<=j<i-1)

很明显超时。

C++ 代码

不能才不会写呢!

算法2(单调队列优化)

因为要找最小的,就可以想到单调队列,里面存储的值就是到那个点的最小代价.

时间复杂度

能过,(肯定不是因为我算不来才不写(⊙o⊙)…)

C++ 代码

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
const int N=1e6+10;
int n,m,l,r;
int a[N],f[N],q[N<<1];
/*
    队列中每个点就是以他自己开头的m个烽火台的最小总代价.
    也可能没有m个,如<m的.
    最后遍历一遍n-m+1~n,取其中最小的.
*/
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    l=r=0;
    for(int i=1;i<=n;i++){
        while(l<r&&i-q[l]>m) l++;//如果不是i个内,就出队.
        f[i]=f[q[l]]+a[i];
        while(l<r&&f[q[r]]>f[i]) r--;
        q[++r]=i;
    }
    int ans=INF;
    for(int i=n-m+1;i<=n;i++) ans=min(ans,f[i]);
    printf("%d",ans);
    return 0;
}
01-06 00:24