题解【AcWing1089】烽火传递
单调队列优化 DP 模板题。
我们考虑设 \(dp_{i}\) 表示从 \(1\) 到 \(i\) 能够准确传递情报,且第 \(i\) 个烽火台发出信号的最小费用。
转移方程不难得出:\(dp_{i} = \min_{i-m \leq j \leq i-1}\{dp_j\} + a_i\)(\(a_i\) 为第 \(i\) 个烽火台发出信号的费用)。
看到转移的条件:\(i-m \leq j \leq i - 1\),这其实就是一个滑动窗口问题。
用一个单调队列维护长度为 \(m\) 的滑动窗口即可。
最后的答案是 \(\min_{n-m-1\leq i \leq n}\{dp_i\}\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 200003;
int n, m, a[N], q[N], hh, tt, ans, dp[N];
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i+=1) cin >> a[i];
    hh = 0, tt = 0; //注意一开始队列中是有元素的
    for (int i = 1; i <= n; i+=1) //对于每一个烽火台进行转移
    {
        while (hh <= tt && q[hh] < i - m) ++hh; //队头是否在区间内
        dp[i] = dp[q[hh]] + a[i]; //DP 值转移
        while (hh <= tt && dp[q[tt]] >= dp[i]) --tt; //维护队列单调性
        q[++tt] = i; //加入队列
    }
    ans = 2000000007; //答案
    for (int i = n - m + 1; i <= n; i+=1) 
        ans = min(ans, dp[i]); //答案要从 n - m + 1 ~ n 的 DP 值中取最小值
    cout << ans << endl;
    return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号