原题链接:1134 最长递增子序列
题目分析:长度为 的数列 有多达 个子序列,但我们应用动态规划法仍可以很高效地求出最长递增子序列()。这里介绍两种方法。
先考虑用下列变量设计动态规划的算法。这里设输入数列的第一个数为 。
一位数组, 为由 到 中的部分元素构成且最后选择了 的 的长度。 | |
一位数组, 为由 到 中的部分元素构成且最后选择了 的 的倒数第二个元素的位置(记录当前以得出的最长递增子序列中,各元素前面一个元素的位置) |
有了这些变量,动态规划法求 的算法便可以这样实现。
LIS()
L[0] = 0
A[0] = 0 // 选择小于 A[1] 到 A[n] 中任意一个数的值进行初始化
P[0] = -1
for i = 1 to n
k = 0
for j = 0 to i - 1
if A[j] < A[i] && L[j] > L[k]
k = j
L[i] = L[k] + 1 // 满足 A[j] < A[i] 且 L[j] 最大的 j 即为 k
P[i] = k // LIS 中 A[i] 的前一个元素为 A[k]
上述动态规划法的复杂度为 ,无法在限制时间内解开 的问题。因此我们需要考虑效率更高的解法。
实际上,只要把动态规划与二分搜索结合起来,就能进一步提高求解最长递增子序列的效率。这种算法要用到下列变量:
一维数组, 表示长度为 的递增子序列的末尾元素最小值 | |
整数,表示前 个元素构成的最长递增子序列的长度 |
LIS()
L[0] = A[0]
length = 1
for i = 1 to n - 1
if L[length] < A[i]
L[length++] = A[i]
else
L[j] (j = 0, 1, ..., length - 1) 中第一个大于等于 A[i] 的元素 = A[i]
#include <iostream>
#include <algorithm>
#define MAX 100000
using namespace std;
long long n, A[MAX + 1], L[MAX];
int lcs() {
L[0] = A[0];
int length = 1;
for (int i = 1; i < n; i++) {
if (L[length - 1] < A[i]) {
L[length++] = A[i];
} else {
*lower_bound(L, L + length, A[i]) = A[i];
}
}
return length;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++)
cin >> A[i];
cout << lcs() << endl;
return 0;
}