再探LIS
昨天讲课的时候突然想起来LIS还有一个东西没搞懂。
又去研究了下。
LIS问题就是要求一个序列中最长不下降或上升子序列,而此问题应用较广,例如很多题会有这样的条件
对于i,j如果他们可以同时选取,则必有|a[i]-a[j]| <= |b[i]-b[j]| (b[i]<b[j])
数学化归一下下得到 b[i]-b[j] <= a[i]-a[j] <= b[j]-b[i]
将i,j各放在一边 有
a[i]-b[i] >= a[j]-b[j]…………①,
a[i]+b[i] <= a[j]+b[j]…………②.
那么我们按其中一个条件排序,即保证排序后的序列对于任意的i,j(i<j)都有①式或②式成立,然后再按另一个条件求LIS即可求出最多可以取多少个。
若要知道取几次可以取完,那么 根据 dilworth 定理, 等同于求其反条件(即原来非降现在就是下降)子序列长度。
那么下面介绍求LIS的几种方法
法一 O(n^2)暴力dp转移
令dp[i]表示以ai结尾的最长不下降子序列长度
则转移方程为dp[i]=max{1,dp[j]+1} a[j]<=a[i]
则max{dp[i]}就是答案
法二 对于上面的dp转移,显然可以用树状数组优化
可以做到(nlogn)
设有 f[i] 表示以大小为i结尾的不下降子序列的最长长度
则dp[i]=max{f[j]}+1,j<=h[i];
max{f[j]}用树状数组维护
具体如下
int g() {
memset(C,,sizeof C);
int ans=;
for(int i=;i<=n;i++) {
dp[i]=;
int t=query(h[i])+;
ans=max(ans,t);
add(h[i],t);
}
return ans;
}
注意:1.可以不保留dp数组,直接更新ans即可。
2.如果max{h[i]}过大,则需要离散化
法三 二分法求LIS O(nlogn)
设s[i]表示以长度为i的上升子序列的最后一位的最小值。
则每次可以用a[i]去更新s[i]数组
显然s数组是不下降的
int h[Maxn],s[Maxn],ans,n;
int f(){
s[ans=]=-INF;
for(int i=;i<=n;i++){
int v=h[i];
if(v>s[ans])s[++ans]=v;
else*lower_bound(s+,s+ans+,v)=v;
}return ans;
}
对于第6行得到新的答案,根据s数组的定义,显然正确。
然后如果v<=s[ans],则此时不能更新ans,但是可以更新s数组,如何更新呢?跟上面一样,我们要找到一个s[i] (< v) 则此时可以用这个s[i]来更新s[i+1],而实际上只有这一个更新是有意义的,因为对于<=i的更新只会使答案更劣,对于i+2及以上的不能保证序列合法。
更新之后就会更新s[i+1]的值,又s[i]是最大的满足s[i]<v的i,所以s[i+1]必是最小的>=v的值,用lower_bound就好了。
同理如果要求非降子序列 改成下面这样即可
int h[Maxn],s[Maxn],ans,n=;
int f(){
s[ans=]=-INF;
for(int i=;i<=n;i++){
int v=h[i];
if(v>=s[ans])s[++ans]=v;
else*upper_bound(s+,s+ans+,v)=v;
}return ans;
}
可以发现改了两处,一是第6行的>= 二是lower_bound变成了upper_bound
请自行思考为什么这样可行
再探LIS的更多相关文章
- 【再探backbone 02】集合-Collection
前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...
- ViewPager+Fragment再探:和TAB滑动条一起三者结合
Fragment前篇: <Android Fragment初探:静态Fragment组成Activity> ViewPager前篇: <Android ViewPager初探:让页面 ...
- 再探jQuery
再探jQuery 前言:在使用jQuery的时候发现一些知识点记得并不牢固,因此希望通过总结知识点加深对jQuery的应用,也希望和各位博友共同分享. jQuery是一个JavaScript库,它极大 ...
- [老老实实学WCF] 第五篇 再探通信--ClientBase
老老实实学WCF 第五篇 再探通信--ClientBase 在上一篇中,我们抛开了服务引用和元数据交换,在客户端中手动添加了元数据代码,并利用通道工厂ChannelFactory<>类创 ...
- Spark Streaming揭秘 Day7 再探Job Scheduler
Spark Streaming揭秘 Day7 再探Job Scheduler 今天,我们对Job Scheduler再进一步深入一下,对一些更加细节的源码进行分析. Job Scheduler启动 在 ...
- 再探ASP.NET 5(转载)
就在最近一段时间,微软又有大动作了,在IDE方面除了给我们发布了Viausl Studio 2013 社区版还发布了全新的Visual Studio 2015 Preview. Visual Stud ...
- 再探java基础——break和continue的用法
再探java基础——break和continue的用法 break break可用于循环和switch...case...语句中. 用于switch...case中: 执行完满足case条件的内容内后 ...
- 第四节:SignalR灵魂所在Hub模型及再探聊天室样例
一. 整体介绍 本节:开始介绍SignalR另外一种通讯模型Hub(中心模型,或者叫集线器模型),它是一种RPC模式,允许客户端和服务器端各自自定义方法并且相互调用,对开发者来说相当友好. 该节包括的 ...
- 深入出不来nodejs源码-内置模块引入再探
我发现每次细看源码都能发现我之前写的一些东西是错误的,去改掉吧,又很不协调,不改吧,看着又脑阔疼…… 所以,这一节再探,是对之前一些说法的纠正,另外再缝缝补补一些新的内容. 错误在哪呢?在之前的初探中 ...
随机推荐
- javascript 之DOM篇
要怎么样的开场白才能使我有力气再更新学习进度呢?啊啊啊啊啊,表示好累啊~~~默念“棒棒棒,我最棒~”召唤精气神开总结敲字咯.哈哈哈. --------------------------------- ...
- hbase的存储体系
一.了解hbase的存储体系. hbase的存储体系核心的有Split机制,Flush机制和Compact机制. 1.split机制 每一个hbase的table表在刚刚开始的时候,只有一个regio ...
- Codeforces 474F - Ant colony
注意到每个区间生存下来的蚂蚁的长度等于区间的gcd 于是可以先预处理出区间的gcd 然后二分查找就好了 预处理gcd我这里用的是倍增法 总的时间复杂度O(NlogN) /* Cf 271F 倍增求区间 ...
- [C#]获取最近在Windows上所使用的文件
class RecentlyFileHelper { public static string GetShortcutTargetFile(string shortcutFilename) { var ...
- Bootstrap_表单_图标
在Bootstrap框架中是通过给元素添加“glyphicon”类名来实现,然后通过伪元素“:before”的“content”属性调取对应的icon编码: <span class=" ...
- js 去除字符串开头或者前几个字符。slice 也可以用于截取某一部分
摘草自w3 slice() 方法可从已有的数组中返回选定的元素. 语法 arrayObject.slice(start,end) 参数 描述 start 必需.规定从何处开始选取.如果是负数,那么它规 ...
- PHP android ios相互兼容的AES加密算法
APP项目用户密码传输一直没有用HTTPS,考虑到用户的隐私暂时先用AES对密码加密,以后也可以用于手机端与服务端加密交互. PHP的免费版phpAES项目,手机端解码各种不对. 好不容易找了PHP ...
- <和>
今天用到>查了查资料就是这么个回事.
- linux配置记录
今天想把开发环境都配置到linux环境来,所以用wubi挂载了个ubuntu系统(64位),因为不常使用linux所以把今天学到的一些 东西记下来以做备查. #1. java环境配置 到oracl ...
- Mvc Controller 单元测试 Mock User.Identity.Name
被测试的Action 包含 User.Identity.Name 代码,在写测试代码需要Mock ControllerContext对象 代码如下: var mock = new Mock<Co ...