最长上升子序列
最长上升子序列是DP的入门题目,解法多样,只介绍(nlog_n)的做法。
其实nlogn的做法不是传统的DP而是贪心。
定理:如果当前已选子序列的最后一位ans[last]有更合适的选择,则该选择a[i]满足(ans[last - 1]< a[i] < ans[last]),所以可以用二分优化查找,来更新已选子序列。
/*#include <bits/stdc++.h>
using namespace std;
int n, data[100010], dp[1001000];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &data[i]), dp[i] = 2147483647;
for (int i = 1; i <= n; i++)
*lower_bound(dp + 1, dp + 1 + n, data[i]) = data[i];
printf("%d", lower_bound(dp + 1, dp + 1 + n, 2147483647) - (dp + 1));
return 0;
}
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100100;
int a[maxn], n, lis[maxn], len;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i = 1; i <= n; i++) cin>>a[i];
lis[++len] = a[1];
for(int i = 2; i <= n; i++)
{
if(a[i] > lis[len])
lis[++len] = a[i];
if (a[i] < lis[len])
{
int pos = lower_bound(lis+1, lis+1+len, a[i]) - lis;//找到第一个比a[i]大的数
lis[pos] = a[i];
}
}
for(int i = 1; i <= len; i++) cout<<lis[i]<<" ";
cout<<endl;
cout<<len;
return 0;
}