最长单增子序列

(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. Spring AOP前置通知实例讲解与AOP详细解析

    一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Service.他们都有sayHello():我们的需求是在调用这两个方法之前,要先完成写日志的 ...

  2. git使用笔记(九)操作原理

    By francis_hao    Nov 27,2016   参考[1]的一张图已经把git的基本原理描述的很清楚了,如下:   下面以实例演示其过程,需要用到两个命令cat-file和ls-fil ...

  3. Ubuntu下安装LNMP之Mysql的安装及卸载

    Mysql的安装过程也可参考:http://blog.csdn.net/qq_20565303/article/details/69813868 Mysql安装包下载地址:https://dev.my ...

  4. Prepare and Deploy Windows Server 2016 Active Directory Federation Services

    https://docs.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/hello-key-t ...

  5. ES6学习笔记(五)—— 编程风格

    1. 块级作用域 let 取代 var —— let 只在声明的代码块内有效,而且不存在变量提升的效用 const 取代 let —— const 比较符合函数式编程的思想,运算不改变值,只是新建值: ...

  6. 基于多线程的TCP socket通信经典案例

    服务器端 package com.thinkvenus.study.socket; import java.io.BufferedReader; import java.io.IOException; ...

  7. 【poj3294-不小于k个字符串中最长公共子串】后缀数组

    1.注意每两个串之间的连接符要不一样. 2.分组的时候要注意最后一组啊!又漏了! 3.开数组要考虑连接符的数量.100010是不够的至少要101000. #include<cstdio> ...

  8. 「6月雅礼集训 2017 Day1」说无可说

    [题目大意] 给出n个字符串,求有多少组字符串之间编辑距离为1~8. n<=200,∑|S| <= 10^6 [题解] 首先找编辑距离有一个n^2的dp,由于发现只找小于等于8的,所以搜旁 ...

  9. DotNETCore 学习笔记 异常处理

    Error Handling public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseIISP ...

  10. Git服务器安装详解及安装遇到问题解决方案【转】

    转自:http://www.cnblogs.com/grimm/p/5368777.html git是一个不错的版本管理的工具.现在自己在搞一个简单的应用程序开发,想使用git来进行管理.在Googl ...