题目描述

时间限制:1.0s 内存限制:256.0MB

问题描述

   给定一个长为\(n\)的序列,求它的最长上升子序列的长度。

输入格式

   输入第一行包含一个整数\(n\)。

   第二行包含\(n\)个整数\(a_1,a_2,…,a_n\),为给定的序列。

输出格式

   输出一个非负整数,表示最长上升子序列的长度。

样例输入

 5
1 3 2 5 4

样例输出

 3

数据规模和约定

   \(0<n\leq10^5\),每个数不超过\(10^6\)。

解析

   所谓最长上升子序列,就是给定一列数,求序列中严格上升的子序列,子序列中数的位置不一定连续。

1.动态规划dp

   这是动态规划中的一个经典应用题目,动态规划的思想就是把问题分解为一些本质上还是相同问题的小问题,这些小问题的区别仅在于输入的参数不同,而每一个小问题的解都可以由比他参数更小的一些小问题的解推出,最小的小问题有显而易见的解,这被称之为边界。最长上升子序列(LIS)问题也是这样。

   \(a_i\)(\(1\leq i<n\))表示序列中第\(i\)个整数

   \(dp_i\) 表示以\(a_i\)为结尾的最长上升子序列的长度

   于是,\(dp_i\)要把\(a_i\)加到以\(a_j\)(\(1\leq j<i\))为上升子序列末尾的后面,并且符合\(a_j<a_i\),找一个最大的dp[j],然后令\(dp_i = dp_j + 1\)即求出了\(dp_i\)。

   最后在所有的\(dp_i\)中取一个最大的即为整个序列的最长上升子序列的长度。

   算法时间复杂度为\(O(n^2)\),当范围大一些的时候是有些低效的。

#include <iostream>
#include <algorithm>
using namespace std;
int a[100005], d[100006];
const int INF = 0x3f3f3f3f;
int main() {
int n; cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
int maxx = -INF;
for (int i = 1; i <= n; i++) {
d[i] = 1;
for (int j = 1; j < i; j++)
if (a[j] < a[i])
d[i] = max(d[i], d[j] + 1);
maxx = max(maxx, d[i]);
}
cout << maxx << endl;
return 0;
}
2.二分搜索优化

   \(a_i\)(\(1\leq i<n\))表示序列中第\(i\)个整数

   \(dp_m\) 表示长度为\(m\)的最长公共子序列的末尾最小值

   当\(i=1\)时,\(dp_i=a_i\)。

   当\(i\)逐渐增加,每次扫过\(a_i\),因为\(dp_m\)代表长度为i的最长上升子序列的最小末尾,这可以代表一个长度为m的最长上升子序列,我们考虑可以把\(a_i\)加到哪个最长上升子序列后面构成一个长度\(+1\)的新的最长上升子序列。那么我们就可以在\(dp\)数组中寻找到\(j\)(\(1\leq j\leq m\))并且\(dp_j<a_i\leq dp_{j+1}\),把\(a_i\)加到这个数代表的序列后面:\(dp_{j+1}=a_i\)。

   因为\(dp\)数组是有序的,所以在进行寻找的时候就可以用二分搜索来进行。而当我们把\(a\)数组全部扫描完之后,\(dp\)数组中的最后一个有效的数字的位置即是我们所求的最长上升子序列的长度\(m\)。

   由于循环中的搜索变成了二分搜索,时间复杂度为\(O(log_n)\),所以整体时间复杂度是\(O(nlogn)\)。

#include <iostream>
#include <algorithm>
using namespace std;
int dp[100005], a[100005];
int b_search(int x, int l, int r) {
while (l < r) {
int mid = (r + l) / 2;
if (dp[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
int main(int argc, char** argv) {
int n; cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
dp[i] = 0x3f3f3f3f;
}
int m = 1;
dp[1] = a[1];
for (int i = 2; i <= n; i++) {
if (a[i] > dp[m]) dp[++m] = a[i];
else {
int j = b_search(a[i], 1, m);
dp[j] = min(dp[j], a[i]);
}
}
cout << m << endl;
return 0;
}

   在第二个算法中我们可以通过在二分查找中改变“上确界”和“下确界”,以及在第一个算法中通过改变符号(“<”和“<=”或“>”、“>=”等),求出最长不下降、不上升、严格下降子序列等问题。

最长公共子序列-LIS的更多相关文章

  1. 最长公共子序列(LCS)和最长递增子序列(LIS)的求解

    一.最长公共子序列 经典的动态规划问题,大概的陈述如下: 给定两个序列a1,a2,a3,a4,a5,a6......和b1,b2,b3,b4,b5,b6.......,要求这样的序列使得c同时是这两个 ...

  2. 算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列

    出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的 ...

  3. 最长递增子序列(lis)最长公共子序列(lcs) 最长公共上升子序列(lics)

    lis: 复杂度nlgn #include<iostream> #include<cstdio> using namespace std; ],lis[],res=; int ...

  4. 最长公共子序列-LCS问题 (LCS与LIS在特殊条件下的转换) [洛谷1439]

    题目描述 给出1-n的两个排列P1和P2,求它们的最长公共子序列. 输入 第一行是一个数n, 接下来两行,每行为n个数,为自然数1-n的一个排列. 输出 一个数,即最长公共子序列的长度 输入样例 5 ...

  5. 最长上升子序列(LIS)与最长公共子序列(LCS)

    1.LIS : 给定一个序列,求它的最长上升子序列(n<=2000) 第一种 O(n^2): dp[i] 为以i为开头的最长上升子序列长度 code1: #include<cstdio&g ...

  6. 最长连续公共子序列(LCS)与最长递增公共子序列(LIS)

    最长公共子序列(不连续) 实际问题中也有比较多的应用,比如,论文查重这种,就是很实际的一个使用方面. 这个应该是最常见的一种了,不再赘述,直接按照转移方程来进行: 按最普通的方式就是,直接构造二维矩阵 ...

  7. 最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

    最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字 ...

  8. 【线型DP模板】最上上升子序列(LIS),最长公共子序列(LCS),最长公共上升子序列(LCIS)

    BEGIN LIS: 一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序 ...

  9. 【LCS,LIS】最长公共子序列、单调递增最长子序列

    单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4   描述 求一个字符串的最长递增子序列的长度如:dabdbf最长递增子序列就是abdf,长度为4   输入 ...

随机推荐

  1. BZOJ 1857: [Scoi2010]传送带(三分套三分)

    Time Limit: 1 Sec Memory Limit: 64 MB Submit: 2549 Solved: 1370 [Submit][Status][Discuss] Descriptio ...

  2. codevs 1300:文件排版(DP)

    题目描述 写电子邮件是有趣的,但不幸的是经常写不好看,主要是因为所有的行不一样长,你的上司想要发排版精美的电子邮件,你的任务是为他编写一个电子邮件排版程序. 完成这个任务最简单的办法是在太短的行中的单 ...

  3. Java初学者作业——编写Java程序,根据输入的某个班级的学员成绩,计算该班级学员的平均成绩,要求输入班级的人数。

    返回本章节 返回作业目录 需求说明: 编写Java程序,根据输入的某个班级的学员成绩,计算该班级学员的平均成绩,要求输入班级的人数. 实现思路: 声明变量sum.count以及avg用于存储总成绩.班 ...

  4. ClickHouse在监控系统中的应用

    一.背景 这个项目是一个监控系统,主要监控主机.网络设备.应用等.主机监控的数量有1500台左右,数量还在不断增长,加上网络设备和应用,目前总共监控的指标达到近40万个. 二.问题 一开始为了快速交付 ...

  5. linux下备份mysql数据

    一.业务场景 自己现在做的项目基本上已经开发完成,正式开始上线运行,主要包含两个子项目一个是小程序的后台,一个是后台管理系统. 正式开始运行一段时间后,基本上也没什么BUG了,整个项目都已经能够正常的 ...

  6. linux 之 误删openssl文件夹重装openssl

    背景 使用 scp.ssh 都报错 error while loading shared libraries: libcrypto.so.1.0.0: cannot open shared objec ...

  7. 初识python: flush 实现进度条打印

    通过flush(强制刷新)实现,类似进度条打印: #!/user/bin env python # author:Simple-Sir # time:20180918 #打印进度条 import sy ...

  8. sqlserver - 判断字段是否是纯数字

    PATINDEX('%[^0-9|.|-|+]%',w.waterMeterNo)=0 如 SELECT w.* FROM [dbo].[waterMeterInfo] w where isnull( ...

  9. dispatcher-servlet.xml文件配置模板

    完整代码如下: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http:/ ...

  10. linux tomcat【9.0.12】 使用 ssl证书 配置 https 的具体操作 【使用 域名 】

    1.前言 根据上一个随笔,已经可以正式在 阿里云服务器发布 工程了 ,但是用的协议默认是 http ,端口80 但是 http不安全 ,容易被拦截抓包 ,于是出来了个 https tomcat发布 对 ...