AcWing3662. 最大上升子序列和(线性DP + 树状数组优化 + 离散化处理)

AcWing3662. 最大上升子序列和(线性DP + 树状数组优化 + 离散化处理)

  • 一、问题
  • 二、分析
    • 1、DP过程
      • (1)状态表示
      • (2)状态转移
    • 2、数据结构优化
      • (1)树状数组维护最值
      • (2)离散化
      • (3)优化过程
  • 三、代码

一、问题

在这里插入图片描述

二、分析

1、DP过程

这道题考察的DP模型是最长上升子序列的模型,如果对这个模型不了解的话,建议去看作者的这一篇文章:第四十三章 动态规划——最长单调序列模型
这里就是对这个模型稍作变形。这里要注意的是:最长的上升子序列的和不一定是最大的。

(1)状态表示

f [ i ] f[i] f[i]表示以第 i i i个元素为结尾的上升子序列的和的最大值。

(2)状态转移

状态转移也比较经典,这里直接给出方程再解释。
f [ i ] = m a x ( f [ i ] ) + a [ i ] f[i] = max(f[i]) + a[i] f[i]=max(f[i])+a[i]
直接去枚举 i i i之前的状态,但是为了保证我们的序列是单调递增的,我们转移的条件需要多一个 a [ j ] < a [ i ] a[j]<a[i] a[j]<a[i]
上述操作的时间复杂度是 O ( n 2 ) O(n^2) O(n2)的。在这道题中,该复杂度会造成超时的错误,所以我们需要对这道题的做法进行优化。对于取最大值的操作我们常用的是单调队列优化,但是这道题随着我们 i i i的移动,我们的转移条件在不断地发生变化,所以无法使用单调队列来优化。

因此,我们只能换一种数据结构来优化了,对于维护一个区间的最值得操作,我们常用的是线段树和 s p l a y splay splay树。而我们这里只需要维护 1 1 1 i − 1 i-1 i1的最大值,也就是说维护的是前缀最大值,很明显,我们的前缀最大值是比区间最大值好维护的,所以我们这里可以使用一个相对于代码量较少的数据结构——树状数组

2、数据结构优化

在讲解优化之前,我们先学习一下前置知识。

(1)树状数组维护最值

如果大家不懂树状数组的作用和代码的话,作者这里建议读者去看作者的文章:第五十六章 树状数组(一)
作者之前的文章中介绍的是如何利用树状数组去动态维护区间和。我们这里则只需要将加和的操作改成去最值即可,其余操作没有区别。

(2)离散化

离散化的本质其实就是将数组中的数据本身映射为下标。我们只需要去将读入的数据进行排序去重,这样就实现了一个数据与下标之间的对应关系。这样的话,当我们遍历数据的时候,只需要采用二分操作就能够在刚刚的映射关系中找到该元素所映射的下标。
如果还不理解的话,可以去看作者之前的文章:第五章:双指针与离散化的映射

(3)优化过程

我们现在的目的是通过较低的复杂度去快速地查询出在第 i i i个元素之前并且小于第 i i i个元素的元素 a [ j ] a[j] a[j],再通过 a [ j ] a[j] a[j]找到这个元素所对的状态 f [ j ] f[j] f[j],然后在这些满足条件的 f [ j ] f[j] f[j]中找到一个最大值。

在这个目的的驱使下,我们可以进行如下优化:
我们将原数组 a a a进行排序得到数组 b b b。那么我们 a a a数组中的元素在 b b b数组中就根据其大小关系得到了一个相对下标,我们根据这个相对下标建立树状数组,树状数组存储的数值就是状态值 f f f

这里要注意的是,我们 f f f状态所对的下标是 a a a数组的下标,但我们却按照 b b b的大小顺序将其存储在了树状数组的特定位置。

上述操作有什么作用呢?

由于我们是按照元素的相对顺序建立的树状数组,所以对于树状数组的任意位置 k k k,这个 k k k前面所有存储的 f [ i ] f[i] f[i]所对的状态 a [ i ] a[i] a[i]都是小于 k k k位置所存状态对应的 a a a的。也就是说,在不考虑原数组 a a a的下标先后顺序的条件下,树状数组 k k k前面所存储的状态都是能够更新当前状态的。

现在的关键在于我们如何保证我们 k k k位置前所存储的状态在原数组 a a a中的下标位置都是小于当前状态在数组 a a a中所对下标的?

这个问题就比较好解决了,因为我们是动态维护的,所以对于 a a a数组中的任意下标 i i i,我们先找到其在 b b b数组中的相对下标 k k k,然后根据刚刚的分析,我们可以先查询树状数组 k k k之前的状态的最大值,查询后去更新当前状态,然后再把当前状态插入树状数组即可。这样做的目的在于我们所用的状态都是之前插入的,而我们是按照 a a a数组下标从小到大枚举的。所以已经插入的状态对应的 a a a数组下标必定是在待更新状态之前的。

离散化算法其实就是针对我们的 b b b数组的,因为 b b b数组存储的是数组元素的相对大小,相同元素的相对位置应该是一样的,所以对于重复元素我们需要去重。这个过程恰好和离散化是一致的,所以我们就可以认为这里用了离散化操作。

三、代码

#include<bits/stdc++.h>
#define endl '\n'
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 10;
int n;
int a[N], f[N], tre[N];
vector<int>xs;

int get(int x)
{
	return lower_bound(xs.begin(), xs.end(), x) - xs.begin() + 1;
}

int lowbit(int x)
{
	return x & -x;
}

void add(int pos, int x)
{
	for(int i = pos; i <= n; i += lowbit(x))
	{
		tre[i] = max(tre[i], x);
	}
}

int quary(int pos)
{
	int res = 0;
	for(int i = pos; i; i -= lowbit(i))
	{
		res = max(tre[i], res);
	}
	return res;
}

void solve()
{
	cin >> n;
	for(int i = 0; i < n; i ++ )
	{
		cin >> a[i];
		xs.push_back(a[i]);
	}
	sort(xs.begin(), xs.end());
	xs.erase(unique(xs.begin(), xs.end()), xs.end());
	for(int i = 0; i < n; i ++ )
	{
		int k = get(a[i]);
		f[i] = quary(k - 1) + a[i];
		add(k, f[i]);
	}
	int ans = 0;
	for(int i = 0; i < n; i ++ )
	{
		ans = max(f[i], ans);
	}
	cout << ans << endl;
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	solve();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K8s 弃用 Docker!一文介绍 containerd ctr、crictl 使用

containerd 是一个高级容器运行时&#xff0c;又名 容器管理器。简单来说&#xff0c;它是一个守护进程&#xff0c;在单个主机上管理完整的容器生命周期&#xff1a;创建、启动、停止容器、拉取和存储镜像、配置挂载、网络等。 containerd 旨在轻松嵌入到更大的系统中。Docke…

【ASPLOS 2023】图神经网络统一图算子抽象uGrapher,大幅提高计算性能

作者&#xff1a;周杨杰、沈雯婷 开篇 近日&#xff0c;阿里云机器学习平台PAI和上海交通大学冷静文老师团队合作的论文《图神经网络统一图算子抽象uGrapher》被ASPLOS 2023录取。 为了解决当前图神经网络中框架中不同的图算子在不同图数据上静态kernel的性能问题&#xff0…

【前沿技术】文心一言 PK Chat Gpt

目录 写在前面 一、文心一言 二、Chat GPT 三、对比 四、总结 写在前面 随着人工智能技术的不断发展和普及&#xff0c;越来越多的智能应用走入了人们的日常生活&#xff0c;如智能语音助手、智能客服、机器翻译等等。在这些应用中&#xff0c;自然语言生成&#xff08;…

看完不再愁 | 图解TCP 重传、滑动窗口、流量控制、拥塞控制

目录 前言 正文 &#x1f332; 重传机制 1. 超时重传 2. 快速重传 3. SACK 方法 4. Duplicate SACK &#x1f332; 滑动窗口 &#x1f333; 流量控制 &#x1f333; 拥塞控制 1. 慢启动 2. 拥塞避免算法 3. 拥塞发生 4. 快速恢复 前言 前面我们讲到「硬不硬你说…

Android开发一直在用大公司的开源库,可参考~

一、阿里巴巴 &#xff08;一&#xff09;UI有关 1. 多页面切换场景统一解决方案 UltraViewPager UltraViewPager 是阿里开源的一个封装多种特性的 ViewPager &#xff0c;主要是为多页面切换场景提供统一解决方案。 主要功能: 1. 支持横向滑动&#xff0f;纵向滑动2. 支持一屏…

求红白黑球的个数-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第2章-课后作业)

【案例2-11】求红白黑球的个数 一、案例描述 考核知识点 for循环语句、if判断语句 练习目标 掌握for循环应用。掌握if判断语句应用 需求分析 用js编程 已知&#xff1a;红白球共25个&#xff0c;白黑球共31个&#xff0c;红黑球共28个&#xff0c;求三种球各有多少&#xff…

基于STM32 SG90 9g舵机控制

文章目录一、什么是舵机&#xff1f;二、工作原理三、利用PWM控制四、stm32舵机控制一、什么是舵机&#xff1f; 产品参数 名称&#xff1a;9克舵机180度 尺寸&#xff1a;23mm X 12.2mm X 29mm 重量&#xff1a;9克 扭矩&#xff1a;1.5kg/cm 工作电压&#xff1a;4.2 - 6V 温…

Java大数字运算(BigInteger类和BigDecimal类)

在 Java 中提供了用于大数字运算的类&#xff0c;即 java.math.BigInteger 类和 java.math.BigDecimal 类。这两个类用于高精度计算&#xff0c;其中 BigInteger 类是针对整型大数字的处理类&#xff0c;而 BigDecimal 类是针对大小数的处理类。 BigInteger 类 如果要存储比 …

一本通 3.3.1 树与二叉树

树与二叉树的基本知识 1336&#xff1a;【例3-1】找树根和孩子 【题目描述】 给定一棵树&#xff0c;输出树的根root&#xff0c;孩子最多的结点max以及他的孩子。 【题目分析】 【代码实现】 #include<bits/stdc.h> using namespace std; int father[201], sum[101]…

8.OSP的GR(Graceful Restart,平滑重启)实验

一、GR(Graceful Restart,平滑重启) 技术介绍 GR(Graceful Restart,平滑重启)技术保证了设备在重启过程中转发层面能够继续指导数据的转发,同时控制层面邻居关系的重建以及路由计算等动作不会影响转发层面的功能,从而避免了路由振荡引发的业务中断,保证了关键业务的数…

Java_Spring:5. 基于注解的 IOC 配置

目录 1 环境搭建 1.1 第一步&#xff1a;拷贝必备 jar 包到工程的 lib 目录。 1.2 第二步&#xff1a;使用Component 注解配置管理的资源 1.3 第三步&#xff1a;创建 spring 的 xml 配置文件并开启对注解的支持 2 常用注解 2.1 用于创建对象的注解 2.1.1 Component 2.1…

【MySQL高级篇】第09章_性能分析工具的使用

第09章_性能分析工具的使用 在数据库调优中&#xff0c;我们的目标是 响应时间更快, 吞吐量更大 。利用宏观的监控工具和微观的日志分析可以帮我们快速找到调优的思路和方式。 1. 数据库服务器的优化步骤 当我们遇到数据库调优问题的时候&#xff0c;该如何思考呢&#xff1…

在vue项目中使用echarts(echarts不显示,echarts使用详细)

简述&#xff1a;我们在写大屏项目和vue项目时经常会用到echarts&#xff0c;用于数据统计和可视化&#xff0c;它是一款基于JavaScript的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表&#xff0c;下面分…

【IAR工程】STM8S208RB基于ST标准库蜂鸣器(BEEP)驱动

【IAR工程】STM8S208RB基于ST标准库蜂鸣器(BEEP)驱动&#x1f33e;寄存器版本《STM8S系列基于IAR开发&#xff1a;蜂鸣器&#xff08;BEEP&#xff09;驱动功能模块示例》&#x1f33f;相关篇《【IAR工程】STM8S208RB基于ST标准库下GPIO点灯示例》&#x1f33f;《【IAR工程】ST…

总结803

早上&#xff1a; 6:44起床 7:00~7:04开合跳100 7:09~8:00小湖读英语 8:00~9&#xff1a;30句句真研 9&#xff1a;40~10:00去教室 10:03~10:15阅读《运动改造大脑》 10:15~12:00上课 12:00~12:20背单词 12:23~12:50吃饭 1:00~2:10午觉 2:30~5:00核聚课程一篇考研英…

HashMap, HashTable, ConcurrentHashMap 之间的区别

目录关于线程安全HashTable 和 ConcurrentHashMap 的区别1. 加锁粒度不同(最关键 最核心的区别!!!)2. ConcurrentHashMap 利用了 CAS 机制 (无锁编程)3. 优化了扩容策略关于线程安全 我们知道 HashMap 是线程不安全的. 如果要在多线程环境下使用哈希表, 则可以使用:HashTable …

深度学习语义分割篇——FCN原理详解篇

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;往期回顾&#xff1a;目标检测系列——开山之作RCNN原理详解    目标检测系列——Fast R-CNN原理详解    目标检测系列——Faster R-CNN原理详解 &#x1f34a;近期目标&…

说微软翻译比谷歌准,有人不信,就拿雾霾造了个句子

导读近年来&#xff0c;谷歌(微博)、微软、亚马逊和Facebook等硅谷巨头在人工智能&#xff08;AI&#xff09;领域进行着军备竞赛。在应用层面&#xff0c;有的开发智能管家、有的做机器人、有的训练AI治疗疾病。谷歌和微软则在翻译领域较上了劲。 长久以来&#xff0c;谷歌翻译…

Redis Stream消息并发和未ack消息处理

文章目录1. RedisStreamConfig2. 消费者MyMessageListener3. RedisStreamUtil4. RedisStreamConstant5. 测试6. 处理消费者已读取未ack的消息redis stream文档参考 https://zhuanlan.zhihu.com/p/60501638 1. RedisStreamConfig package com.tophant.eventdemo.common.config…

CSS3笔试题精讲1

防止父元素高度坍塌 4种方案 父元素的高度都是由内部未浮动子元素的高度撑起的。 如果子元素浮动起来,就不占用普通文档流的位置。父元素高度就会失去支撑,也称为高度坍塌。 即使有部分元素留在普通文档流布局中支撑着父元素,如果浮动 起来的元素高度高于留下的素。那么浮…
最新文章