题目描述:
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
输入格式
第一行包含整数N。第二行包含N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。
数据范围
1≤N≤1000,−10^9≤数列中的数≤10^9
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
分析:
设用数组a[n]存储该数列,很容易想到用f[i]表示前i + 1个数中的最长上升子序列的长度,但是如何由规模为n - 1的问题的解求出规模为n的问题呢?比如2 1 5 3中,最长上升子序列为1 3,1 5和2 5,长度为2,如果在序列后面再追加一个4,我们知道,每个上升子序列都有一个末尾元素,只有4大于该末尾元素才能够使得该上升子序列长度加1,所以以4为末尾的上升子序列有2 4,1 4,3 4,1 3 4,然后最长的长度是3,于是2 1 5 3 4的最长上升子序列长度是3。在求解过程中,我们只需要知道两个信息,一个是4可以加到哪些序列后面,另一个是加在哪个序列后面使得以4为末尾的子序列长度最长。比如4加在3后面,3之前的是什么元素对4而言并不重要,我们只需要知道以3为末尾的最长上升子序列长度是多少即可,因此,我们每在一个序列后加一个元素,需要知道之前的序列以每个元素为结尾的最长上升子序列长度是多少,设b[i]表示以a[i]为结尾的最长上升子序列长度,则只要新加入的元素>a[i],就可以扩展该上升子序列的长度。然后max(b[i])即是数列中最长上升子序列的长度。
本题给我们的启示是,如果f数组的含义直接按最优解设递推不方便,不妨换种设法,找到了以i为末尾的最长上升子序列长度,遍历一遍,就得到了题目的最优解。
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1005;
int a[maxn],b[maxn];
int main(){
int n,res = 0;
cin>>n;
for(int i = 0;i < n;i++) cin>>a[i];
for(int i = 0;i < n;i++){
int t = 0;
for(int j = 0;j < i;j++){
if(a[i] > a[j]) t = max(b[j],t);
}
b[i] = t + 1;
}
for(int i = 0;i < n;i++) res = max(res,b[i]);
cout<<res<<endl;
return 0;
}