B3637's Solution
B3637's Solution最长上升子序列
题目描述
这是一个简单的动规板子题。
给出一个由 \(n(n\le 5000)\) 个不超过 \(10^6\) 的正整数组成的序列。请输出这个序列的最长上升子序列的长度。
最长上升子序列是指,从原序列中按顺序取出一些数字排在一起,这些数字是逐渐增大的。
输入格式
第一行,一个整数 \(n\),表示序列长度。
第二行有 \(n\) 个整数,表示这个序列。
输出格式
一个整数表示答案。
样例 #1
样例输入 #1
6
1 2 4 1 3 4
样例输出 #1
4
提示
分别取出 \(1\)、\(2\)、\(3\)、\(4\) 即可。
思路:
简单DP,这是一道简单DP题,用来入门DP挺不错。
考虑这么一件事:首先,对于每一个元素来说,最长上升子序列就是其本身,且长度为\(1\)。
那么,我们只需要维护 \(dp[i]\),使得 \(dp[i]\)代表以第 i 个元素结尾的最长上升子序列的长度,显然,对于每个 \(dp[i]\) 来说,初始值为\(1\)。
那么\(dp\) 数组怎么求?
我们可以对于每一个 \(i\) 枚举在 \(i\) 之前的所有元素 \(j\) ,如果元素 \(j > i\) 并且 \(dp[i] < dp[j] + 1\) 则继承,最优解是对每个继承来的 \(dp\) 值取 \(max\)。
for (int i = 1; i <= n; i++) cin >> a[i], dp[i] = 1; // 简单输入 + 初始化
for (int i = 1; i <= n; i++) { // 枚举每个元素 i
for (int j = 1; j < i; j++) { //枚举元素 i 前的每一个元素 j
// 满足元素 i > j 并且 满足 dp[i] < dp[j] + 1 则继承
// 注意 dp数组 表示的是子序列的长度,且 dp数组初始值是1
// 显然,需要满足 dp[i] < dp[j] + 1 一定要加 1
if (a[i] > a[j] && dp[i] < dp[j] + 1) dp[i] = dp[j] + 1;
}
}
sort(dp + 1, dp + 1 + n);
cout << dp[n];
于是,我们得到了 \(O(n^2)\) 的做法,代码如下:
#include <bits/stdc++.h>
using namespace std;
int n, a[5005], dp[5005];
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i], dp[i] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (a[i] > a[j] && dp[i] < dp[j] + 1) dp[i] = dp[j] + 1;
}
}
sort(dp + 1, dp + 1 + n);
cout << dp[n];
}
但是,时间复杂度不够优秀,
一旦, \(n\) 大一点,就会 \(TLE\) ……
于是有了 \(O(nlogn)\) 的做法:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, inf = 1e9 + 10;
int f[N], a[N];
int n, ans;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i], f[i] = inf;
f[1] = a[1];
ans = 1;
for (int i = 2; i <= n; i ++) {
if (a[i] > f[ans]) f[++ ans] = a[i];
else f[lower_bound(f + 1, f + ans + 1, a[i]) - f] = a[i];
}
cout << ans << '\n';
}
优化 \(O(nlogn)\) 做法:
#include <bits/stdc++.h>
using namespace std;
int n, a[5005], dp[5005];
signed main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i], dp[i] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
if (a[i] > a[j] && dp[i] < dp[j] + 1) dp[i] = dp[j] + 1;
}
}
sort(dp + 1, dp + 1 + n);
cout << dp[n];
}