【洛谷 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;
}
相关推荐
小程故事多_804 小时前
从A2C、TRPO、PPO到GRPO,强化学习策略梯度算法完整演进与大模型落地实战解析
人工智能·算法
2601_956121975 小时前
二分算法(知识点+题目)
c++·算法
AndrewHZ8 小时前
【LLM技术全景】阶段总结:技术原理篇核心知识回顾
人工智能·深度学习·算法·语言模型·大模型·llm·芯片开发
小星星闪亮登场9 小时前
2026萌新联赛第三场-- (郑州轻工业大学)
数据结构·c++·经验分享·算法·贪心算法·排序算法·深度优先
冻柠檬飞冰走茶9 小时前
PTA基础编程题目集 7-8超速判断(C++语言实现)
开发语言·数据结构·c++·算法
玖玥拾10 小时前
LeetCode 88 合并两个有序数组
算法·leetcode
数据皮皮侠AI10 小时前
上市公司数字供应链金融指数(2010-2024)
大数据·人工智能·算法
2501_9423895510 小时前
Epoch AI旗下FrontierMath的负责人Elliot Glazer
数据结构·决策树·动态规划·散列表
小程故事多_8010 小时前
用GRPO算法重塑多智能体系统,从原理落地到复杂任务规划实战
人工智能·算法
Hi李耶11 小时前
【LeetCode】541.反转字符串 II
算法·leetcode·职场和发展