您的位置:首页 > 其它

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

2016-11-02 21:33 281 查看
题目描述 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: