给出长度为N的数组,找出这个数组的最长递增子序列。(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10。
收起
输入
第1行:1个数N,N为序列的长度(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9)
输出
输出最长递增子序列的长度。
输入样例
8
5
1
6
8
2
4
5
10
输出样例
5
奈何码农没文化 一手暴力行天下(手动滑稽) 第一反应是暴力解题 可是暴力解题的时间复杂度为 O(n^2) 想起来 当时做最长上升字串(51nod 1006 最长公共子序列)觉得dp 可以解 然会就看是简单dp 最后 TLE (天噜啦)第一次写的代码如下
#include<iostream>
#include<cmath>
using namespace std;
const int N = 50000+5;
typedef long long ll;
ll num[N];
int dp[N];
int Dp(int n){
int ans = 0;
for(int i = 1; i < n ; i++){
for(int j = 0; j < i;j++){
if(num[j] < num[i])
dp[i] = max(dp[j]+1,dp[i]);
ans = max(dp[i],ans);
}
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
for(int i = 0; i < n ; i++){
scanf("%lld",&num[i]);
dp[i] = 1;
}
int ans = Dp(n);
printf("%d\n",ans);
return 0;
}
写完了提交 过了15 个样例 看了看代码 明显是披着dp外衣的暴力 emmmm 然后想到了一个自认为绝佳的方法
思路是这样 既然是求最长上升子序列 那就把每个长度的上升子序列的最后一个字母记录下来然后这是数组的长度 不就是最长上升子序列的长度 语言有时候是苍白的 上代码
#include<iostream>
using namespace std;
const int MAX_N = 1e5;
int dp[MAX_N];
int num[MAX_N];
int Dp(int n){
int len = 1;
dp[len] = num[0];
for(int i = 1; i < n;i++){
if(num[i] > dp[len]){
dp[++len] = num[i];
}else{
int pos = lower_bound(dp+1,dp+len,num[i])-dp;
dp[pos] = num[i];
}
}
return len;
}
int main()
{
int n;
scanf("%d",&n);
for(int i = 0; i < n ;i++){
scanf("%d",&num[i]);
}
int ans = Dp(n);
for(int i = 0; i < ans ;i++){
printf("%d",dp[i]);
}
printf("\n");
printf("%d\n",ans);
return 0;
}
这次 就AC 了 看来还是不能过度依赖模板 还是得学会变通