最长单增子序列

(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. LA4273 Post Offices

    题目戳这里. 村庄排序.状态\(f[j][i]\)表示考虑前\(i\)个村庄,造\(j\)个邮局且\(i\)造了邮局的最小代价.我们用\(Lb_i,Rb_i\)表示在第\(i\)个村庄造邮局,邮局最左 ...

  2. Codeforces Round #523 (Div. 2) A. Coins

    A. Coins 题目链接:https://codeforc.es/contest/1061/problem/A 题意: 给出n和s,要在1-n中选数(可重复),问最少选多少数可以使其和为s. 题解: ...

  3. hadoop之HDFS与MapReduce

    Hadoop历史 雏形开始于2002年的Apache的Nutch,Nutch是一个开源Java 实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具.包括全文搜索和Web爬虫. 随后在2003 ...

  4. MySQL远程访问权限 允许远程连接

    1 首先cd / 到根目录,打开mysql控制台 登录数据库  mysql -u root -p 2.授权远程连接 mysql> use mysql; Database changed mysq ...

  5. iOS 后台运行执行代码(例如定位)

  6. java基础知识(二)-----多态和构造函数

    一:前言 最近由于面试了新浪公司,面试官问我的问题我都不知道,觉得自己好菜,所以最近决定再把java基础给搞一遍,真的觉得自己好菜.每天看一点,那个家伙说<java编程思想>最少要看三遍, ...

  7. oracle有关游标的知识

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

  8. L2-001. 紧急救援---(Dijkstra,记录路径)

    https://www.patest.cn/contests/gplt/L2-001 L2-001. 紧急救援 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 ...

  9. 【洛谷 P1437】 [HNOI2004]敲砖块 (DP)

    题目链接 毒瘤DP题 因为\((i,j)\)能不能敲取决于\((i-1,j)\)和\((i-1,j+1)\),所以一行一行地转移显然是有后效性的. 于是考虑从列入手.我们把这个三角形"左对齐 ...

  10. 【洛谷 SP283】NAPTIME - Naptime(DP)

    题目链接 先考虑如果只有一天,那么该怎么做. 设\(f[i][j][1]\)表示前\(i\)个小时睡了\(j\)个小时并且第\(j\)个小时正在睡觉时的最大体力,\(f[i][j][1]\)表示前\( ...