【洛谷 B3637】最长上升子序列 题解(动态规划+耐心排序+lower_bound+最长上升子序列)

最长上升子序列

题目描述

这是一个简单的动规板子题。

给出一个由 n ( n ≤ 5000 ) n(n\le 5000) n(n≤5000) 个不超过 1 0 6 10^6 106 的正整数组成的序列。请输出这个序列的最长上升子序列的长度。

最长上升子序列是指,从原序列中按顺序 取出一些数字排在一起,这些数字是逐渐增大的。

输入格式

第一行,一个整数 n n n,表示序列长度。

第二行有 n n n 个整数,表示这个序列。

输出格式

一个整数表示答案。

样例 #1

样例输入 #1

复制代码
6
1 2 4 1 3 4

样例输出 #1

复制代码
4

提示

分别取出 1 1 1、 2 2 2、 3 3 3、 4 4 4 即可。


思路

首先,定义一个整数 n 来存储序列的长度,和一个整数数组 a 来存储序列的元素。同时,定义一个长整型数组 dp 来存储动态规划的状态,dp[i] 存储的是长度为 i 的上升子序列的最小末尾元素。

main 函数中,首先读取序列的长度 n,然后读取序列的元素。然后,对序列的每个元素进行处理,找到在 dp 数组中第一个大于或等于当前元素的位置 pos。这里使用了 lower_bound 函数,这是一个标准库中的二分查找函数。如果 pos 大于当前的最长上升子序列的长度 len,则更新 len。最后,将当前元素放在 dp 数组的 pos 位置。

dp[i] 存储的是长度为 i 的上升子序列的最小末尾元素。当遍历到一个新的元素时,如果这个元素大于所有已有的上升子序列的末尾元素,则可以将这个元素接在最长的上升子序列后面,形成一个更长的上升子序列。否则,找到一个已有的上升子序列,它的末尾元素大于或等于这个元素,然后用这个元素替换那个末尾元素。这样做的目的是尽可能地使上升子序列的末尾元素小,以便有更多的机会接上新的元素。

最后,输出最长上升子序列的长度 len


AC代码

cpp 复制代码
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;

const int N = 1e6 + 7;

int n;
int a[N];
ll dp[N];

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

	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}

	int len = 0;
	for (int i = 1; i <= n; i++) {
		int pos = lower_bound(dp + 1, dp + len + 1, a[i]) - dp;
		len = max(len, pos);
		dp[pos] = a[i];
	}
	cout << len << "\n";
	return 0;
}
相关推荐
1000世界小札9 小时前
《大话数据结构》第9章精读:归并排序与快速排序完整 C++ 实现
数据结构·c++·算法
2601_9561219711 小时前
背包基础篇(01、完全、分组、多重、混合)
c++·算法·动态规划
兴通物联科技12 小时前
SMT PCB 微小 DataMatrix 码扫不动问题分析 兴通 XT8601B 600 万像素工业读码器落地实践
大数据·人工智能·单片机·嵌入式硬件·算法·计算机视觉
月华路15 小时前
G1 GC 对数组与大对象(Humongous)的处理
java·jvm·算法
我想走路带风15 小时前
LRU和最长前缀和(计算机网络算法)
计算机网络·算法
M78佐菲15 小时前
Linux学习笔记:进程
linux·笔记·学习·算法
徐小夕17 小时前
表格、文档、甘特、大屏、表单一站打通:pxcharts超级表格4.0正式上线!
前端·算法·github
TechLee18 小时前
跨语言加解密总对不上?这个纯 Go 神库让 AES/RSA 与 PHP、Java 100% 互通
java·后端·算法
月华路19 小时前
G1 新生代对象晋升老年代:实现机制与 GC 日志
java·jvm·算法