再探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源码-内置模块引入再探
我发现每次细看源码都能发现我之前写的一些东西是错误的,去改掉吧,又很不协调,不改吧,看着又脑阔疼…… 所以,这一节再探,是对之前一些说法的纠正,另外再缝缝补补一些新的内容. 错误在哪呢?在之前的初探中 ...
随机推荐
- JDBC标准事物编程模式
事物简介: 事物是一种数据库中保证交易可靠的机制,JDBC支持数据库中事物的概念,默认情况下事物是默认提交的. 事物的特性: 1.事物必须是原子工作单元,对于其数据的修改,要么都执行,要么都不执行2. ...
- hdoj 1686 kmp
题目: Sample Input 3 BAPC BAPC AZA AZAZAZA VERDI AVERDXIVYERDIAN Sample Output 1 3 0 代码: #in ...
- Direct 2D实现界面库 (2)
Direct 2D实现界面库 (1) http://www.cnblogs.com/mmc1206x/p/3924580.html 上篇说完了每个 LNode 的绘制过程. 也就是 onDraw 的实 ...
- grep操作
这个程序的名称来自Unix文本编辑器ed类似操作的命令: g/re/p 这个命令搜索整个文件中匹配给定正则表达式的文本行,并显示出来.有很多不同的命令行用于改变grep的默认行为,包括显示出不匹配的文 ...
- 入门3:PHP环境开发搭建(windows)
一.环境需要 硬件环境(最低配置): 双核CPU 8G内存 操作系统环境: Windows(64位)7+ Mac OS X 10.10+ Linux 64位(推荐Ubuntu 14 LTS) /**拓 ...
- TatukGIS-TGIS_ShapeArc.GetPointOnLine
function GetPointOnLine(const _distance: Double; const _offset: Double; const _part: Integer): TGIS_ ...
- 如何“任性”使用Android的drawText()
Android的canvas上可以画很多基本形状,诸如:圆,矩形,线条等等,其中当属文字即drawText()较难理解和使用(额,这只是就个人感受),下面将慢慢介绍下如何简单使用drawText(). ...
- xamarin fivechess
网上的五子棋项目是java开发,先转为xamarin,有需要的请下载. FiveChess.7z
- Annikken Andee–Arduino与Android间的简易连接
一个Arduino的兼容板,允许你显示并控制来自Android设备的Arduino应用.无需Anroid APP开发. 点击:观看视频 什么是Annikken Andee? Annikken Ande ...
- PKU 1064 Cable master
题目链接:点击打开链接 有n段绳子,给定n段绳子的长度,单位为厘米.求能够把这些绳子分成k段的最长的段的长度.题目中的trick是最小是1cm,长度不能小于1cm,因此要转换成int来解,然后二分可以 ...