浅谈最长上升子序列(LIS)
一、瞎扯的内容
给一个长度为n的序列,求它的最长上升子序列(LIS)
简单的dp
n=read();
for(i=;i<=n;i++) a[i]=read();
for(i=;i<=n;i++)
for(j=;j<i;j++)
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+);
printf("%d",dp[n]);
然后发现
看来需要一个nlogn求LIS的算法
二、不瞎扯的内容
上一个算法慢在哪里呢?内层的循环
如果把它变成二分查找不就是nlogn的算法了吗
为此需要进行一下改动
dp数组改为存储长度为i的上升子序列中最小的末尾数字
这样每当外层循环到了一个新的数字
若
a[i]>dp[len]//新的数字比当前LIS的末尾数字大
则
dp[++len]=a[i]//愉快地把这个数字接到后面
如果它小于等于dp[len]?
举个例子
序列2 3 1
i=1:找到2,当前LIS={2},没毛病;
i=2:找到3,发现它比LIS的最后一个数字大,把它接到后面,当前LIS={2,3};
i=3:找到1,发现它比3小,那么在当前的LIS中找到一个最小的比1大的数,也就是2,并把2替换成1,当前LIS={1,3}
Q1:为什么可以这么做呢?
我们现在把2替换成了1,如果接下来还能把3替换,我们就可以得到一个更优的LIS
为什么更优?首先LIS是保证尽可能长的,在此基础上,末尾数字越小越优
Q2:如何在当前的LIS中找到一个最小的比a[i]大的数?
根据“长度一定时,末尾数字越小结果越优”原则,dp数组一定是递增的
这个递增就不做证明了,应该比较好想
所以就可以用二分查找了
问题解决
for(i=;i<=n;i++) dp[i]=0x7fffffff;
dp[]=a[];
int len=,l,r,mid;
for(i=;i<=n;i++)
{
if(a[i]>dp[len]) dp[++len]=a[i];
else
{
l=;r=len;
while(l<=r)
{
mid=(l+r)>>;
if(dp[mid]>a[i]) r=mid-;
else l=mid+;
}
dp[l]=min(dp[l],a[i]);
} }
三、来道题
题目简述:给出两个1~n的序列,求他们的最长公共子序列(n≤100000)
这跟LIS有什么关系呢?
还真有关系
不妨改为在第二个序列中匹配第一个序列,最多匹配多少
由于两个序列都是1~n的,可将第一个序列重新定义一下
比如 3 2 1 4 5
3----1;2----2;1----3;4----4;5----5(对应到它是第几个)
那么第二个序列 1 2 3 4 5就会变成3 2 1 4 5
这时再求最长公共子序列的答案是一样的
然而可以发现第一个序列已经变成了1~n的升序排列,那么第二个序列的子序列 也是第一个序列的子序列的充要条件 是 它是一个上升的序列
那么问题就变成了求第二个序列的LIS
用上述方法可以解决
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std; inline int read()
{
int f=,x=;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
} int n;
int a[],b[],f[],g[]; int main()
{
int i;
n=read();
for(i=;i<=n;i++)
{
a[i]=read();
g[a[i]]=i;
}
for(i=;i<=n;i++)
{
b[i]=read();
b[i]=g[b[i]];
f[i]=0x7fffffff;
}
f[]=b[];
int len=,l,r,mid;
for(i=;i<=n;i++)
{
if(b[i]>f[len]) f[++len]=b[i];
else
{
l=;r=len;
while(l<=r)
{
mid=(l+r)>>;
if(f[mid]>b[i]) r=mid-;
else l=mid+;
}
f[l]=min(f[l],b[i]);
}
}
printf("%d\n",len);
return ;
}
~祝大家学习信息学顺利~
BJOI 加油!
浅谈最长上升子序列(LIS)的更多相关文章
- 浅谈最长上升子序列(O(n*logn)算法)
今天GM讲了最长上升子序列的logn*n算法,但没讲思路... 我看了篇博客,发现-- 说的有道理!!! 首先,举例子: a[7]={1,2,4,3,6,7,5}(假设以1开头) 很明显,LIS=5: ...
- 2.16 最长递增子序列 LIS
[本文链接] http://www.cnblogs.com/hellogiser/p/dp-of-LIS.html [分析] 思路一:设序列为A,对序列进行排序后得到B,那么A的最长递增子序列LIS就 ...
- 最长上升子序列LIS(51nod1134)
1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递 ...
- 动态规划(DP),最长递增子序列(LIS)
题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...
- 【部分转载】:【lower_bound、upperbound讲解、二分查找、最长上升子序列(LIS)、最长下降子序列模版】
二分 lower_bound lower_bound()在一个区间内进行二分查找,返回第一个大于等于目标值的位置(地址) upper_bound upper_bound()与lower_bound() ...
- 题解 最长上升子序列 LIS
最长上升子序列 LIS Description 给出一个 1 ∼ n (n ≤ 10^5) 的排列 P 求其最长上升子序列长度 Input 第一行一个正整数n,表示序列中整数个数: 第二行是空格隔开的 ...
- 最长回文子序列LCS,最长递增子序列LIS及相互联系
最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...
- 一个数组求其最长递增子序列(LIS)
一个数组求其最长递增子序列(LIS) 例如数组{3, 1, 4, 2, 3, 9, 4, 6}的LIS是{1, 2, 3, 4, 6},长度为5,假设数组长度为N,求数组的LIS的长度, 需要一个额外 ...
- 1. 线性DP 300. 最长上升子序列 (LIS)
最经典单串: 300. 最长上升子序列 (LIS) https://leetcode-cn.com/problems/longest-increasing-subsequence/submission ...
随机推荐
- linux日志过滤某时间段的日志
sed -n '/2019-01-10 16:00*/,/2019-01-10 18:48*/p' nohup.out > 111.log
- maven build pulgin
<build> <defaultGoal>compile</defaultGoal> <plugins> <!-- 生成清单文件相关 --> ...
- 企业级Docker-Harbor
[环境准备] # yum install -y yum-utils device-mapper-persistent-data lvm2 下载docker-ce版本的yum源 # yum-config ...
- bool值的底层应用场景
这里我们的if 或者while,还有and,or,not 等都是在内部调用一个对象的bool方法,然后返回True或者是False, a = [0, ] # a = [] # print(bool(a ...
- 蓝桥杯 全球变暖(dfs)
标题:全球变暖 [题目描述]你有一张某海域NxN像素的照片,"."表示海洋."#"表示陆地,如下所示: 其中"上下左右"四个方向上连在一起的 ...
- Skeleton Screen -- 骨架屏--应用
案例:使用 现已经在支付的项目使用 用户体验一直是前端开发需要考虑的重要部分,在数据请求时常见到锁屏的loading动画,而现在越来越多的产品倾向于使用Skeleton Screen Loading( ...
- ASP.NET Core 3.0预览版体验
目前.NET Core 3.0的版本为.NET Core 3.0 Preview 3,对应ASP.NET Core 3.0 Preview 3. ASP.NET Core 3.0 之后将不再支持.NE ...
- 取消layUI中日期选择控件默认填充日期
input标签中使用日期选择控件填写,加载时默认填充当前日期, 标签设置了placeholder="请选择" autocomplete="off",但是并没有效 ...
- java SSM 解决跨域问题
什么是跨域 跨域是指从一个域名的网页去请求另一个域名的资源.比如从www.baidu.com 页面去请求 www.google.com 的资源.跨域的严格一点的定义是:只要 协议,域名,端口有任何一个 ...
- clipboard.js一个可以在移动端一键复制的插件
网址:https://clipboardjs.com/ 使用方法: 1.引入js <script src="dist/clipboard.min.js"></sc ...