Openjudge 1759:最长上升子序列

dp 做法

我们设 \(f_i\) 表示以第 \(i\) 格为结尾得最长上升子序列的长度。先来看样例。

数组 \(a\)1 7 3 5 9 4 8

数组 \(f\)1 2 2 3 4 3 4

我们枚举 \(i\),然后看 \(i\) 之前的第 \(j\) 位 (\(j \le i\)),判断 \(a_j\) 是否小于 \(a_i\),然后就有转移方程

\[f_i = \max(f_i, f_j + 1) \]

初始化:\(f_i = 1\)。因为每个元素自己就是一个序列,所以初始化是 \(1\)

代码

#include<iostream>
using namespace std;
int n, a[1005], f[1005];
int ans;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n; i++) {
                f[i] = 1;
		for (int j = 1; j <= i; j++) { // 枚举 j
			if (a[j] < a[i])
				f[i] = max(f[i], f[j] + 1); // 状态转移方程
			ans = max(ans, f[i]); // 取最大值
		}
	}
	cout << ans;
	return 0;
} 

O(nlogn)

\(n \ge 10^5\) 的时候,dp 的做法就很危险。于是,我们就有了 \(O(nlogn)\) 的做法。

更改 \(f\) 数组的定义。设 \(f_i\) 表示长度为 \(i\) 的最长上升子序列的最小的结尾数字。

来看前面的样例。

数组 \(a\)1 7 3 5 9 4 8

\(i = 1\)\(f\) 数组加入元素 1

\(i = 2\)\(7 > 1\),将 7 加入 \(f\)

\(i = 3\)\(3 < 7\),将 7 替换成 3

\(i = 4\)\(5 > 3\),将 5 加入 \(f\)

\(i = 5\)\(9 > 5\),将 9 加入 \(f\)

\(i = 6\)\(4 < 9\),将 \(f\) 中的 5 替换成 4。注意,这里不会因为数组顺序而改变结果,因为我们改变的是第一个大于当前这个数的位置。如果当前这个数是 \(a\) 中的最后一位,那么答案就是当前数组的长度,如果不是最后一位,那么后面还有数字,可以替换掉 \(f\) 数组当前的最后一位,如果没有能替换掉 \(f\) 的数字,那么 \(f\)最大长度没有被变化过,答案依旧保持不变。

\(i = 7\)\(8 < 9\),将 \(f\) 中的 9 替换成 8

最终,\(f=\{1,3,4,8\}\)

根据以上的推测,我们得出了求出 \(f\) 的方法。

如果当前数字大于 \(f\) 的最后一个数字,那么直接接上,否则就替换在 \(f\) 中第一个大于当前这个数的位置,原理就是让越后面的数字越小,使得能接的数越多。

要找到第一个大于当前这个数的位置,我们可以使用 C++ 的upper_bound()来计算。不懂upper_bound()的可以看一下这个

最终答案就是 \(f\) 数组的长度。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int n, a[5003], s[5003]; // s[i] 表示以 i 为长度所结尾的最长上升子序列的末尾元素 
int ans, cntp = 1;

int main() {
	cin >> n; 
	for (int i = 1; i <= n; i++) cin >> a[i];
	s[1] = a[1]; // 初始化 
	for (int i = 2; i <= n; i++) {
		if (a[i] > s[cntp]) s[++cntp] = a[i]; // 如果大于最长上升子序列的末尾元素 那么直接接在末尾就好 
		else *upper_bound(s + 1, s + cntp + 1, a[i]) = a[i]; // 否则替换第一个大于 a[i] 的数
		// 使得前面的元素较小,这样后面就能接更多的元素 
	}
	cout << cntp;
	return 0;
}

整篇文章讲的是针对严格上升的最长上升子序列,即不存在大于等于,但具体要求还是要看每一个题目的要求,需要随机应变。

posted @ 2025-03-27 12:25  Panda_LYL  阅读(47)  评论(0)    收藏  举报