最长单增子序列

(LIS Longest Increasing Subsequence)给定一个数列,从中删掉任意若干项剩余的序列叫做它的一个子序列,求它的最长的子序列,满足子序列中的元素是单调递增的。

输入

第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
 
请选取你熟悉的语言,并在下面的代码框中完成你的程序,注意数据范围,最终结果会造成Int32溢出,这样会输出错误的答案。
不同语言如何处理输入输出,请查看下面的语言说明。
【分析】
我们现在简单讲一下一个O(nlogn)的算法。我们假象一下dp[i][j]表示前i项时构成长度为j的单调子序列的话,最后一项最小的时候是多少。
如果没有长度为j的单调子序列,则设置为+∞。

我们证明dp[i], 随着j的增长单调递增(不考虑无穷大的时候)
初值dp[0][0] = -∞表示长度为0的单调子序列可以达到无穷小。显然dp[0]只有一项值,它是单调递增的。假设dp[i – 1]是单调递增的:
即 dp[i – 1][0] < dp[i – 1][1] < dp[i – 1][2] < dp[i – 1][3] <..<dp[i – 1][x] 
其实我们可以加一项dp[i – 1][x + 1] = +∞

所以 :
dp[i – 1][0] < dp[i – 1][1] < dp[i – 1][2] < dp[i – 1][3] <..<dp[i – 1][x]  < dp[i – 1][x + 1]


们考虑a[i]这一项有什么用。我们需要找到dp[i – 1][y] < a[i]把它接到长度为y的子序列后面,形成一个长度为y +
1的子序列。如果dp[i – 1][y + 1] < a[i], 这说明不属于a[i]这一项,我们考虑前个数也可以形成长度为y +
1的单增子序列,且最后一项更小,所以我们不应该更新它。事实上我们需要找到dp[i – 1][y] < a[i]  && dp[i – 1][y + 1] >= a[i], 这样把a[i]接在长度为y的子序列后面形成一个长度为(y + 1)的子序列,同时结尾更小。
于是我们有递推关系:

dp[i][0..y] = dp[i – 1][0..y]
dp[i][y + 1] = a[i]
dp[i][y + 2..] = dp[i – 1][y + 2…]

实际上我就更新了一个值,而更新的这个值的递推式,也同时证明了这个序列的单调性。
y的存在性,由于我们添加了 -∞和+∞,我们一定能找到满足上述条件的y值。而且根据单调性,我们可以利用二分查找的方法找到这个临界的y值。注意最后找到的y有可能就等于x,然后我们更新的时候,会更新dp[x + 1] = a[i],这样子序列的长度增长了1。

因为每次只更新一个值,我们dp数组只存第二维就可以了。最终的结果,其实是max {x| dp[x] < +∞}的x。
时间复杂度,二分是O(logn),所以总时间复杂度是O(nlogn)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <stack>
#include <vector>
#include <set>
#include <queue>
using namespace std;
int n,a[],d[],i,j,len;
int binsearch(int x)
{
int l = , r = len, mid;
while (l <= r)
{
mid = (l + r) >> ;
if (d[mid-] <= x && x < d[mid]) return mid;
else if (x > d[mid]) l = mid + ;
else r = mid - ;
}
}
int main()
{
scanf ("%d", &n);
for (i = ; i<= n; i++)
scanf ("%d", &a[i]);
memset (d, , sizeof (d));
d[] = a[];
len = ;
for (i = ; i <= n; i++)
{
if (a[i] < d[]) j = ;
else if (a[i] > d[len]) j = ++len;
else j = binsearch (a[i]);
d[j] = a[i];
}
printf ("%d\n", len);
return ;
}

下面的代码只能过四分之一的数据,因为超时。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <stack>
#include <vector>
#include <set>
#include <queue>
using namespace std;
int main()
{
int n,len,i,j,dp[];
int a[];
cin>>n;
for(i=; i<n; i++)cin>>a[i];
int maxn=;dp[]=;
for(int i=; i<n; i++)
{
dp[i]=;
for(int j=; j<i; j++)
{
if(a[i]>a[j])
{
dp[i]=max(dp[i],dp[j]+);
}
}
maxn=max(maxn,dp[i]);
}
cout<<maxn<<endl;
return ;
}

51nod 最长单增子序列(动态规划)的更多相关文章

  1. 51nod 最长公共子序列问题(动态规划)(LCS)(递归)

    最长公共子序列问题 输入 第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000) 输出 输出最长的子序列,如果有多个,随意输出1个. 输入示例 abcicba abdkscab 输 ...

  2. - > 动规讲解基础讲解七——最长单增子序列

    (LIS Longest Increasing Subsequence)给定一个数列,从中删掉任意若干项剩余的序列叫做它的一个子序列,求它的最长的子序列,满足子序列中的元素是单调递增的. 例如给定序列 ...

  3. 【ACM】最长公共子序列 - 动态规划

    最长公共子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列.tip:最长公共子序列也称作最 ...

  4. 最长上升子序列(动态规划递推,LIS)

    1759:最长上升子序列 题目: 总时间限制: 2000ms 内存限制: 65536kB 描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的 ...

  5. C++求解汉字字符串的最长公共子序列 动态规划

        近期,我在网上看了一些动态规划求字符串最长公共子序列的代码.可是无一例外都是处理英文字符串,当处理汉字字符串时.常常会出现乱码或者不对的情况. 我对代码进行了改动.使用wchar_t类型存储字 ...

  6. [LeetCode] 300. 最长上升子序列 ☆☆☆(动态规划 二分)

    https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-she-ji-fan ...

  7. 51nod 最长递增子序列

    nlogn版最长递增子序列.线段树.(其实常数蛮大的....) #include<iostream> #include<cstring> #include<algorit ...

  8. 九度OJ 1533 最长上升子序列 -- 动态规划

    题目地址:http://ac.jobdu.com/problem.php?pid=1533 题目描述: 给定一个整型数组, 求这个数组的最长严格递增子序列的长度. 譬如序列1 2 2 4 3 的最长严 ...

  9. 300. Longest Increasing Subsequence(LIS最长递增子序列 动态规划)

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

随机推荐

  1. C++——内存使用

    内存分配方式: (1)从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量,static变量. (2)在栈上创建.在执行函数时,函数内局部变量的存储单 ...

  2. C&C++——库头文件及其作用

    1. 一些头文件的作用::ANSI C.提供断言,assert(表达式):GCC.GTK,GNOME的基础库,提供很多有用的函数,如有数据结构操作函数.使用glib只需要包含:GCC.文件夹操作函数. ...

  3. nodejs npm insttall 带不带-g这个参数的区别

    -g 中的g是global的意思所以带-g这个参数是全局安装,不带-g这个参数是本地安装. 在windows系统中全局安装的目录在:C:\Users\linsenq\AppData\Roaming\n ...

  4. ansible+docker

    1.准备镜像: 1007 docker run -itd --name client2 ff37bc5ab732 1008 docker run -itd --name client ff37bc5a ...

  5. PowerDesigner使用教程(转)

    PowerDesigner是一款功能非常强大的建模工具软件,足以与Rose比肩,同样是当今最著名的建模软件之一.Rose是专攻UML对象模型的建模工具,之后才向数据库建模发展,而PowerDesign ...

  6. oracle有关游标的知识

    一:前言 今天我自己第二次写游标,我擦,觉得自己在数据库方面需要很大的提高啊.今天遇到三个问题,第一个是oracle数据库中的数据拆分的问题,这个我用regexp_substr来进行解决,第二个问题就 ...

  7. [POJ1423]Stirling公式的应用

    Stirling公式: n!约等于sqrt(2*pi*n)*(n/e)^n 另外,e约等于2.71828182845409523... 试了一下发现math库里面并不能像pi一样直接调e但是发现挺好记 ...

  8. bzoj 1001 平面图转对偶图 最短路求图最小割

    原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=1001 整理了下之前A的题 平面图可以转化成对偶图,然后(NlogN)的可以求出图的最小割( ...

  9. C# 从服务器下载文件

    一.//TransmitFile实现下载 protected void Button1_Click(object sender, EventArgs e) { /* 微软为Response对象提供了一 ...

  10. hdu 1399 Starship Hakodate-maru (暴力搜索)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1399 题目大意:找到满足i*i*i+j*(j+1)*(j+2)/6形式且小于等于n的最大值. #inc ...