算法提高-动态规划-单调队列优化DP

news2025/1/11 14:42:56

单调队列优化DP

    • AcWing 135. 最大子序和
    • AcWing 1087. 修剪草坪
    • AcWing 1089. 烽火传递
    • AcWing 1090. 绿色通道

关于单调队列的初始化
在这里插入图片描述

AcWing 135. 最大子序和

注意hh = 0,tt = -1 tt = 0初始化的时候队列有什么不同,主要还是要理解队列的实际意义
在这里插入图片描述

#include <iostream>
using namespace std;

typedef long long LL;
const int N = 3 * 1e5 + 10;
int q[N];
LL s[N];

int n, m;
int main()
{
    cin >> n >> m;
    //预处理前缀和数组
    for (int i = 1; i <= n; ++ i) 
    {
        cin >> s[i];
        s[i] += s[i - 1];
    }
    
    LL res = -1e9;//不能初始化为0,因为s[]可能小于0
    //维护单调队列
    
    //如果不把s[0]先放进来,res一开始就会置为0,这在负数的时候不正确 
    //比如这个样例:
    //6 4
    //-1 -3 -5 -1 -2 -3
    //但是如果这么写就可以了 if (i != 0) res = max(res, s[i] - s[q[hh]]);
    // int hh = 0, tt = -1;
    // //q[++tt] = 0;//先把s[0]放进来
    // for (int i = 0; i <= n; ++ i)
    // {
    //     if (hh <= tt && i - q[hh] > m) hh ++;
    //     res = max(res, s[i] - s[q[hh]]);
    //     while (hh <= tt && s[i] <= s[q[tt]]) tt --;
    //     q[++tt] = i;
    // }
    
    
    
    int hh = 0, tt = -1;
    q[++tt] = 0;//先把s[0]放进来
    for (int i = 1; i <= n; ++ i)//s[0]已经放进去了,从1开始就行了
    {
        if (hh <= tt && i - q[hh] > m) hh ++;
        res = max(res, s[i] - s[q[hh]]);
        while (hh <= tt && s[i] <= s[q[tt]]) tt --;
        q[++tt] = i;
    }
    
    cout << res;
    return 0;
}

AcWing 1087. 修剪草坪

#include <iostream>

using namespace std;

const int N = 1e5 + 10;
typedef long long LL;

LL f[N];//从1到i,不选第i个的最小损失的效率
int q[N];
int n, m;
LL res = 1e18 + 7, ans = 0;//res要开到1e18 + 7,开小了过不了
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i)
    {
        cin >> f[i];//在这里我们直接用f[i]来存一下数据,这样可以少开一个数组
        ans += f[i];
    }
    
    int hh = 0, tt = 0;//相当于默认吧s[0] = 0放进去了
    
    for (int i = 1; i <= n; ++ i)
    {
        if (hh <= tt && i - q[hh] > m + 1) hh ++;//不能连续选m个,转化为每m+1个必须选一个不选,
        f[i] += f[q[hh]];//在队列长度还没到m+1之前,q[hh] = 0,f[q[hh] 也是 0,
                         //当i-q[hh]达到m+1时就会每次循环叠加一个f[q[hh]],保证每m+1头牛有一头不选的同时损失的效率最小
        while (hh <= tt && f[i] <= f[q[tt]]) tt --;//经过上一步叠加后,f[i]已经不是之前的f[i]了,
                                                  //如果此时叠加后的f[i]比队尾维护的损失效率更小,那么队尾的数据没用了,直接出队
        q[++tt] = i;//不能是tt++,因为一开始q[hh]是0,如果tt++会用1覆盖掉最初的q[hh]
    }
    
    for (int i = n - m; i <= n; ++ i)//n-m ~ n是m + 1头牛,我们经过上一个完整的for循环后此时的f[i]就是我们定义的:从1到i,不选第i个的最小损失的效率
    {                                //最后m+1头牛中我们选择一头不选就行了,不需要res+=是因为此时的f[i]经过我们的预处理已经是叠加后的值
        res = min(res, f[i]);
    }
    cout << ans - res;
    return 0;
}

AcWing 1089. 烽火传递

在这里插入图片描述

在这里插入图片描述

#include <iostream>

typedef long long LL;

using namespace std;

const int N = 1e6 + 10;
LL s[2 * N];//计算每个点加油量- 耗油量的前缀和,如果s[j] - s[i] < 0;说明从i到j亏油了,不能从i到j,
            //我们要找的就是i ~ i+n-1或者i-(n-1) ~ i这个区间里是否有最小的s[j]使得s[j]-s[i]>=0,如果最小的都>=0那么这个区间内的其他地点肯定也可以顺利到达
            //如何找一个区间内最小的s[j]呢,这就用到了单调队列,我们维护一个区间的单调队列s[q[hh]]就是这个区间内最小的s[j]
int mark[N], q[N * 2], oli[N], d[N];
    
int n;        
int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++ i) cin >> oli[i] >> d[i];
    
    //顺时针游行
    
    
    for(int i = 1;i <= n;i ++) s[i] = s[i + n] = oli[i] - d[i];//表示i地点加的油和到下一地点消耗的油的差
    for (int i = 1; i <= 2 * n; ++ i) s[i] += s[i - 1];//顺时针游行的时候是从1到n,这个游行顺序的话我们前缀和也是给后面的加上前面的数列之和
    
     /*
    顺时针游行从大到小遍历的原因:
    比如计算到i=6这个点时,需要的数据是6~13这个区间内的的前缀和,从6~13这个区间内找一个最小的s[j] - s[6]看是否满足>=0
    如果从小到大遍历,那么队列中并不会存在6~13这个区间内的前缀和,存在的是从-1~6这个区间的前缀和
    所以要从大到小进行枚举遍历
    */
    int hh = 0, tt = -1;
    for (int i = 2 * n; i >= 1; -- i)
    {
        if (hh <= tt && q[hh] > i + (n - 1)) hh ++;//从i到q[hh]这个地点总地点数超过了n(包括i和q[hh]这两个地方)
        while (hh <= tt && s[q[tt]] >= s[i]) tt --;
        q[++ tt] = i;
        //因为我们是环绕一圈,起点是i终点也是i,所以队列里要包含i这个点,所以添加完i入队后我们再if判断是否合法
        if (i <= n && s[q[hh]] - s[i - 1] >= 0) mark[i] = 1;//因为我们计算s[i]的时候根据题意是当前点的加油量-到下一地点的蚝油量,所以这里-s[i - 1]就行了
    }
    
    
    
    //逆时针游行
    hh = 0, tt = -1;
    
    d[0] = d[n];s[1]计算的时候需要
    for(int i = 1;i <= n;i ++) s[i] = s[i + n] = oli[i] - d[i - 1];//逆时针反正开,所以s[i]应该是当前点的加油量-当前点到前面点的距离
    for (int i = 2 * n; i >= 1; -- i) s[i] += s[i + 1]; //逆时针游行的时候是从n到1,这个游行顺序的话我们前缀和是给前面的加上后面的数列之
    
    for (int i = 1; i <= 2 * n; ++ i)//逆时针的时候我们需要的s是s[1]~s[n],顺时针的时候是s[n]~s[2 * n]
    {
    	//注意这里是q[hh] < 不是 >,因为逆时针的时候目的地在出发地的前面
        if (hh <= tt && q[hh] < i - (n - 1)) hh ++;//从i到q[hh]这个地点总地点数超过了n(包括i和q[hh]这两个地方)
        while (hh <= tt && s[q[tt]] >= s[i]) tt --;
        q[++ tt] = i;
        //因为我们是环绕一圈,起点是i终点也是i,所以队列里要包含i这个点,所以添加完i入队后我们再if判断是否合法
        if (i >= n && s[q[hh]] - s[i + 1] >= 0) mark[i - n] = 1;//因为我们计算s[i]的时候根据题意是当前点的加油量-到下一地点的蚝油量,
                                                            //但是我们是逆时针游行,所以我们的上一个地点的下标其实是i+1所以这里-s[i + 1]就行了
    }
    
    for (int i = 1; i <= n; ++ i)
    {
        if (mark[i]) cout << "TAK" << endl;
        else cout << "NIE" << endl;
    }
    return 0;
}
#include<iostream>

using namespace std;

const int N = 2 * 1e5 + 10;
int w[N], q[N];
int f[N];//表示以i为右端点的前缀区间,并且点燃i烽火台的总代价最小是多少
int n, m;
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) cin >> w[i];
    
    int hh = 0, tt = 0;
    for (int i = 1; i <= n; ++ i)
    {
        if (hh <= tt && i > q[hh] + m) hh ++;//保证队列里面就m个
        f[i] = f[q[hh]] + w[i];
        while (hh <= tt && f[q[tt]] >= f[i]) tt --;
        q[++tt] = i;
    }
    if (hh <= tt && (n + 1) > q[hh] + m) hh ++ ;//将队列的右端点移动到n+1的位置(即点燃了第n+1个烽火台),说明在n+1这个虚拟的烽火台的前面的n个烽火台都已经可以沟通了
                                                //在这个区间中找一个f[i]既符合题意:可以使n个烽火台进行交流
                                                //也可以直接用f[q[hh]]找到这个区间内最小的总代价
                                                //因为w[n+1]默认是0,所以点染它没有代价
    cout << f[q[hh]];
    return 0;
}

AcWing 1090. 绿色通道

这题的队列长度最小值(最少空几题)是我们自己不断二分试出来的,二分判断的性质就是如果为了空limit题至少需要多少分钟去写题目,看看这个时间有没有超过题目给的时间,没超过题目给的时间就是合法的

#include <iostream>
using namespace std;

const int N = 5 * 1e4 + 10;// == 5e4 + 10

int f[N];//表示以i为右端点的前缀区间,并且写第i题后一共花费多少时间
int w[N], q[N];
int n, m;

bool check(int limit)
{
    int hh = 0, tt = 0;
    for (int i = 1; i <= n; ++ i)
    {
        if (hh <= tt && i > q[hh] + limit + 1) hh ++;
        f[i] = f[q[hh]] + w[i];//q[hh]是上一个写作业的地方
        while (hh <= tt && f[q[tt]] >= f[i]) tt --;
        q[++tt] = i;
    }
    
    if (n + 1 > q[hh] + limit + 1) hh ++;
    return f[q[hh]] <= m;//类似上一题烽火那题
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) cin >> w[i];
    int l = 0, r = n;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;//求的是最小的mid,因此往左边二分
        else l = mid + 1;
    }
    cout << r;

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/782300.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用python绘制二维向量图

为了实现地层数据的变化趋势的可视化模拟&#xff0c;最近研究了python环境下的可视化方案&#xff0c;为后续的流体运动的仿真模拟做好储备&#xff0c;主要采用matplotlib中的quiver函数&#xff0c;实现二维等值线数据的随深度或者地层数据的变化趋势绘制。 一、运行环境&a…

MySQL--主从复制

目录 1.理解MySQL主从复制原理。 2.完成MySQL主从复制。 1.理解MySQL主从复制原理。 1.主要基于MySQL二进制日志 2.主要包括三个线程&#xff08;2个I/O线程&#xff0c;1个SQL线程&#xff09; 概括&#xff1a; 1、MySQL将数据变化记录到二进制日志中&#xff1b; 2、Slave…

【前端动画】点击移动放大出现蒙版,点击蒙版原路返回 css动画animation

<template><div><!-- 蒙版 Mask--><divv-if"isShowTableMask":class"${maskClass}"click"closeTableMask"></div><div style"" class"table-dialog" :class"${centerTableClass} …

Pytorch从入门到精通:二、dataset与datalodar

数据是深度学习的基础&#xff0c;一般来说&#xff0c;数据量越大&#xff0c;训练出来的模型也越强大。如果现在有了一些数据&#xff0c;该怎么把这些数据加到模型中呢&#xff1f;Pytorch中提供了dataset和dataloader&#xff0c;让我们一起来学习一下吧&#xff0c;datase…

AcWing 237. 程序自动分析

输入样例&#xff1a; 2 2 1 2 1 1 2 0 2 1 2 1 2 1 1输出样例&#xff1a; NO YES 解析&#xff1a; 并查集&#xff0c;由于 i, j 数据量为1e9&#xff0c;所以需要离散化。 数组要开2e5个&#xff0c;由于可能每条“约束条件”的数据都不一样。 #include<bits/stdc.h&…

Python-Go python模块与包 - GO问题 - GO容量测试

目录 go 模块与包复习&#xff08;Init函数 - go mod&#xff09; init函数有什么用&#xff1f;init函数是什么&#xff1f; go.mod文件是什么&#xff1f;有什么作用&#xff1f; python的模块与包 python中包的分类 1、内置模块&#xff1a;不需要安装&#xff0c;直接…

和chatgpt学架构04-路由开发

目录 1 什么是路由2 如何设置路由2.1 安装依赖2.2 创建路由文件2.3 创建首页2.4 编写HomePage2.5 更新路由配置2.6 让路由生效 3 测试总结 要想使用vue实现页面的灵活跳转&#xff0c;其中路由配置是必不可少的&#xff0c;我们在做开发的时候&#xff0c;先需要了解知识点&…

lwip-2.1.3自带的httpd网页服务器使用教程(四)POST类型表单的解析和文件上传

上一篇&#xff1a;lwip-2.1.3自带的httpd网页服务器使用教程&#xff08;三&#xff09;使用CGI获取URL参数&#xff08;GET类型表单&#xff09; 在阅读本篇内容之前&#xff0c;请修改httpd.c文件&#xff0c;修复lwip自带httpd服务器里面关于post的一个bug&#xff1a;bug…

系统集成|第一章(笔记)

目录 第一章 信息化知识1.1 信息与信息化1.1.1 信息1.1.2 信息系统1.1.3 信息化1.1.4 国家信息化体系要素 1.2 国家信息化战略和规划1.3 电子政务1.4 企业信息化和两化深度融合1.4.1 企业信息化1.4.2 企业应用集成1.4.2.1 电子商务系统1.4.2.2 企业资源规划系统1.4.2.3 客户关系…

【Java】 服务器cpu过高如何排查和解决?

文章目录 前言一、常见能够引起CPU100%异常的情况都有哪些&#xff1f;二、服务器CPU使用率飙升异常&#xff0c;黄金4步排查法三、排查 CPU 故障的常用命令四、什么场景会造成 CPU 低而负载确很高呢&#xff1f;五、监控发现线上机器内存占用率居高不下&#xff0c;如何分析进…

两个数组的dp问题--动态规划

一)最长公共子序列: 1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 一)定义一个状态表示:根据经验题目要求 1)选取第一个字符串[0&#xff0c;i]区间以及第二个字符串[0&#xff0c;j]区间作为研究对象&#xff0c;先选取两段区间研究问题&#xff0c;先求出[0…

redis(8):java连接redis

1 Jedis所需要的jar包依赖 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.1.0</version></dependency> 2 Jedis常用操作 2.1 测试连通性 package com.example.demo;import redis.…

手写Spring,理解SpringBean生命周期

按照Spring使用习惯&#xff0c;准备环境 ​ 首先&#xff0c;写一个TigerApplicationContext&#xff0c;模拟Spring的Annotation Application。然后写一个config&#xff0c;接着写一个UserService。 由于Spring需要扫描bean&#xff0c;所以我们得定义一个扫描注解Componen…

【C++】-priority_queue(优先级队列的具体使用和模拟实现)以及仿函数的简单介绍

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

ubuntu 开启 ssh 服务 设置root远程登录

设置root用户密码 sudo passwd root安装ssh服务和vim编辑器 sudo apt -y install openssh-server vim开启ssh服务 sudo vim /etc/ssh/ssh_config去掉 配置文件中 Port 22 的注释后保存退出 设置root用户远程登录 sudo vim /etc/ssh/sshd_config将 PermitRootLogin prohibit-pas…

文章审核之敏感词过滤

技术选型 DFA实现原理 DFA全称为&#xff1a;Deterministic Finite Automaton,即确定有穷自动机。 存储&#xff1a;一次性的把所有的敏感词存储到了多个map中&#xff0c;就是下图表示这种结构 敏感词&#xff1a;冰毒、大麻、大坏蛋 工具类 最下面的main方法是测试用的&a…

vuejs源码之解析器

解析就是将模版解析成AST。 <div id"app"><p>{{num}}</p> </div>比如下面这个代码&#xff0c;然后转成AST之后是这个样子。 它是用javascript对象来描述一个接待您&#xff0c;一个对象表示一个节点。对象中的属性用来保存节点所需的各种数…

Docker基本概念+命令

Docker基本概念命令 一、Docker是什么&#xff1f;二、为什么Docker技术受欢迎三、Docker核心概念四、Docker安装五、Docker镜像操作1.搜索镜像2.获取镜像3.镜像加速下载4.查看镜像信息5.查看下载的镜像文件信息6.查看下载到本地的所有镜像7.获取镜像的详细信息8.修改镜像标签9…

【复盘与分享】第十一届泰迪杯B题:产品订单的数据分析与需求预测

文章目录 题目第一问第二问2.1 数据预处理2.2 数据集分析2.2.1 训练集2.2.2 预测集 2.3 特征工程2.4 模型建立2.4.1 模型框架和评价指标2.4.2 模型建立2.4.3 误差分析和特征筛选2.4.4 新品模型 2.5 模型融合2.6 预测方法2.7 总结 结尾 距离比赛结束已经过去两个多月了。 整个过…

手机变局2023:一场瞄准产品和技术的“思维革命”

以折叠屏冲高端&#xff0c;已成为中国手机厂商们的共识。 在这个苹果未涉足的领域&#xff0c;国产手机厂商们加快脚步迭代推新&#xff0c;积极抢占机遇。但平心而论&#xff0c;虽然国产折叠屏机型众多&#xff0c;但市场上始终缺乏一款突破性的产品作为标杆&#xff0c;为…