一本通——单调队列优化dp合集 (烽火传递 最大连续和....)

本文详细介绍了如何使用单调队列优化动态规划问题,以解决烽火传递、最大连续和等算法题目。通过实例解析,阐述了单调队列的工作原理和维护方法,帮助读者掌握在特定问题中利用单调队列提高效率的技巧。
摘要由CSDN通过智能技术生成

1、
烽火传递

在这里插入图片描述
在这里插入图片描述

朴素的dp过程不难理解,dp[i]表示:考虑前i个烽火台 且第i个点燃状态下的最小代价。
dp[i]=min(dp[j])+a[i] ( i-m<=j<=i-1)

j的范围:在考虑i之前,i前面的m个元素,必须取1个,比如i=7,m=3 ,考虑i=7之前,4 5 6中必须取1个。

用单调队列可以优化这种类问题。

所谓单调队列 ,就是 不断地向缓存数组里读入元素,也不时地去掉最老的元素,不定期的询问当前缓存数组里的最小的元素。
保证每次查询区间最值时可以用O(1)时间查到。

维护单调队列时,对于新元素,我们先按照单调性从队尾删去部分元素,再让新元素入队,保证单调性不变 。然后由于更新队首,把超出区间长度的元素丢出去。

注:单调队列存的是数组下标,不是真的存值。而且队头到队尾的元素,也就是下标是递增的,表示入队的时间先后。

//#pragma comment(linker, "/STACK:102400000,102400000")//手动扩栈
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<math.h>
#include<set>
#include<deque>
#include<unordered_map>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int INF=0x3f3f3f3f;
const double eps=1e-5;
const int maxn=2e5+7;
deque<int> dq;//单调队列 递增
LL dp[maxn];//前i个烽火台 且第i个点燃的最小代价
int n,m,v[maxn];
int main()
{
   
//    ios::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
   
        scanf("%d",v+i);
    }
    dq.push_front(0);//这题我们初始化队列为0,可以保证前m个当中不会取超过2个元素
    for(int i=1;i<=n;i++)
    {
   
        dp[i]=v[i];
        if(dq.size()) dp[i]+=dp[dq.front()];
        //入队
        while(dq.size() && dp[dq.back()]>dp[i]) dq.pop_back();
        dq.push_back(i);
        //队首出队
        while(dq.size() && dq.front()<i-m+1) dq.pop_front();
    }
    LL ans=dp[n];
    for(int i=n-1;i>n-m;i--) ans=min(ans,dp[i]);
    cout<<ans;
    //system("pause");
    return 0;
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值