【洛谷 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;
}
相关推荐
Coovally AI模型快速验证25 分钟前
MMYOLO:打破单一模式限制,多模态目标检测的革命性突破!
人工智能·算法·yolo·目标检测·机器学习·计算机视觉·目标跟踪
可为测控1 小时前
图像处理基础(4):高斯滤波器详解
人工智能·算法·计算机视觉
Milk夜雨1 小时前
头歌实训作业 算法设计与分析-贪心算法(第3关:活动安排问题)
算法·贪心算法
BoBoo文睡不醒2 小时前
动态规划(DP)(细致讲解+例题分析)
算法·动态规划
apz_end2 小时前
埃氏算法C++实现: 快速输出质数( 素数 )
开发语言·c++·算法·埃氏算法
仟濹3 小时前
【贪心算法】洛谷P1106 - 删数问题
c语言·c++·算法·贪心算法
CM莫问4 小时前
python实战(十五)——中文手写体数字图像CNN分类
人工智能·python·深度学习·算法·cnn·图像分类·手写体识别
sz66cm4 小时前
LeetCode刷题 -- 45.跳跃游戏 II
算法·leetcode
Amor风信子4 小时前
华为OD机试真题---战场索敌
java·开发语言·算法·华为od·华为
old_power5 小时前
【PCL】Segmentation 模块—— 基于图割算法的点云分割(Min-Cut Based Segmentation)
c++·算法·计算机视觉·3d