【洛谷 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;
}
相关推荐
xu_yule19 分钟前
算法基础—组合数学
c++·算法
爱尔兰极光20 分钟前
LeetCode--移除元素
算法·leetcode·职场和发展
Tansmjs32 分钟前
C++中的工厂模式变体
开发语言·c++·算法
naruto_lnq34 分钟前
多平台UI框架C++开发
开发语言·c++·算法
Tingjct35 分钟前
十大排序算法——交换排序(一)
c语言·开发语言·数据结构·算法·排序算法
MM_MS37 分钟前
Halcon图像点运算、获取直方图、直方图均衡化
图像处理·人工智能·算法·目标检测·计算机视觉·c#·视觉检测
每天要多喝水41 分钟前
贪心算法专题Day22
算法·贪心算法
ujainu1 小时前
Flutter + OpenHarmony 游戏开发进阶:动态关卡生成——随机圆环布局算法
算法·flutter·游戏·openharmony
PPPPPaPeR.1 小时前
程序地址空间
linux·算法
苦藤新鸡1 小时前
51.课程表(拓扑排序)-leetcode207
数据结构·算法·leetcode·bfs