题目描述 Description
给一个数组a1, a2 … an,找到最长的上升降子序列ab1< ab2< .. < abk,其中b1< b2<..bk。
输出长度即可。输入描述 Input Description
第一行,一个整数N。
第二行 ,N个整数(N < = 1000000)输出描述 Output Description
输出K的极大值,即最长不下降子序列的长度样例输入 Sample Input
5
9 3 6 2 7样例输出 Sample Output
3数据范围及提示 Data Size & Hint
n<=1000000
为了方便大家调试,数据名称已被修改——THREE
题解:我们一般求最长上升子序列需要枚举前面的答案转移过来,复杂度是O(n^2),对于这道题来说显然不够。这道题我们修改一下dp数组的含义,不再是存以第i个数结尾的最长上升子序列长度,而是长度为i的子序列的最小结尾的数。然后我们就可以利用二分查找来做这个题。如果对于上面的说明不明白的话,博主强烈推荐每次更新完dp数组就输出一次看一看,非常有利于理解!方法我也写在了代码里。
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=10100000;
int a[1000010],dp[1000010];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(dp,63,sizeof(dp));//初始化
for(int i=1;i<=n;i++)
{
dp[lower_bound(dp+1,dp+n+1,a[i])-dp]=a[i];//二分查找第一个大于等于a[i]的数,并把a[i]插入
/*
for(int j=1;j<=n;j++)
{
if(dp[j]==1061109567) printf("-1 ");
else printf("%d ",dp[j]);
}
printf("\n");
*/
}
printf("%d\n",(lower_bound(dp+1,dp+n+1,inf)-dp-1));//输出最长的子序列长度
return 0;
}