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];
}
posted @ 2022-10-13 10:32  Furthe77oad  阅读(126)  评论(0编辑  收藏  举报