codevs 3955 最长严格上升子序列(加强版)(DP)

题目描述 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;
}
发布了81 篇原创文章 · 获赞 2 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Loi_YZS/article/details/53012962