这几天dp写得难受……

在讨论这个问题之前,首先明确:“子序列”是指从原序列中挑选出若干元素,按照原序列中的顺序组成新的序列(区别于“子串”,即从原序列中挑选连续的一段)。

要解决这个问题,一个直接的思路是动态规划(Dynamical Programming):
以dp[i]dp[i]表示前ii个元素中的最长递增子序列的长度,那么有如下的状态转移方程:

dp[i]=max{dp[j]+1|0≤j<i and a[i]>a[j]}

dp[i]=max\{dp[j]+1|0\le j\lt i\space and\space a[i]\gt a[j]\}特殊地,令dp[0]=0dp[0]=0
时间复杂度为O(n2)O(n^2),在数据规模较大时容易tle,怎么办?
\\ \\
\\ \\
\\ \\
\\ \\
注意到在每次求dp[i]dp[i]时,该算法都要向前搜索一个之前问题的最优解,但是是否所有子问题的解都对答案有意义呢?
考虑:当子问题的解中有两个递增子序列长度相同时,我们能否删去一个?
\\ \\
\\ \\
因为我们的任务是求解之后的子问题,所以对于前面子问题解中两个长度相同的递增子序列,取结尾元素较小的那个一定不更坏,因为这样可以给后面的问题留下更多的余地。
那么我们將dpdp数组修改一下,让dp[i]dp[i]表示当前找到的长度为ii的递增子序列序列的结尾元素值。那么状态转移方程可修改为:

lis(i)=max{j+1|0≤j<i and dp[j]<a[i]}

lis(i)=max\{j+1|0\le j\lt i\space and\space dp[j]初始化时令dp[0]=−INFdp[0]=-INF,dp[i]=INF(0<i≤n)dp[i]=INF(0\lt i\le n)
每次求出lis(i)lis(i)后更新dp[lis(i)]=min(dp[lis(i)],a[i])dp[lis(i)]=min(dp[lis(i)],a[i])
这样改完对于最终答案不是很大的问题已经有很高的效率了,但是时间复杂度仍为O(n2)O(n^2),有没有什么办法降低复杂度呢?
\\ \\
\\ \\
试着将此时的dpdp数组输出出来,可能你已经想到了,它是单调递增的……
为什么?这不是废话吗!?要是最优的长度为3的递增子序列的末尾元素大于最优的长度为4的递增子序列末尾元素,那长度为4的子序列究竟是哪冒出来的?
\\ \\
\\ \\
利用这一性质,我们可以将第二层循环改成二分搜索,时间复杂度降低为O(nlogn)O(n\log^n)……

应用:HDU1025

#include <cstdio>
#include <algorithm>using namespace std;#define NMAX 500000int m[NMAX+1];
int dp[NMAX+1];int main(){int n;int tp,tr,tmp,mx;int i,ybz;for(ybz=1;scanf("%d",&n)!=EOF;ybz++){for(i=1;i<=n;i++){scanf("%d%d",&tp,&tr);m[tp]=tr;dp[i]=NMAX+10;}mx=1;for(i=1;i<=n;i++){tmp=upper_bound(dp+1,dp+mx+1,m[i])-dp;//printf("%d\n",tmp);dp[tmp]=m[i];if(tmp>mx)mx=tmp;}printf("Case %d:\n",ybz);if(mx==1)printf("My king, at most 1 road can be built.\n\n");else printf("My king, at most %d roads can be built.\n\n",mx);}return 0;
}

尾声

算法的优化是很重要的能力,在刚开始可能无从下手,或者“优化到了同样甚至更高的复杂度”,但是只有有对最优执着不懈的追求,才能让正解一步步水落石出……

CCNU ACM 2016夏季集训·最长递增子序列(LIS)相关推荐

  1. CCNU ACM 2016夏季集训·day1比赛

    表示这比赛坑好多-- 题目页面 咳,总之在各种特殊的wa姿势之间摸爬滚打终于完成了这8道题-- 题解时间到~ A 最小公倍数 求a1a_1,a2a_2,-,ana_n共n个数的最小公倍数. 关键:若x ...

  2. CCNU ACM 2016夏季集训·day3比赛

    表示塔萌大学生智商好高,居然能搞出这么耗脑筋的题(详见C题)--先膜再发题解-- A 发工资咯:) 有面值为壹佰元.伍拾元.拾元.伍元.贰元.壹元的人民币,问付给他人xx元(xx为正整数)最少需多少纸 ...

  3. 耐心排序之最长递增子序列(LIS)

    目录 一.问题引入 1.最长递增子序列(LIS) 2.问题分析 3.代码实现 4.问题思考 二.耐心排序 1.基本介绍 2.操作步骤 3.代码实现 三.俄罗斯套娃信封问题 1.题目描述 2.问题分析 ...

  4. python最大连续递增子列_最长递增子序列(LIS)解法详述

    求数组中最长递增子序列(Longest Increasing Subsequence, LIS) LIS问题是算法中的经典题目,传统的解法是使用动态规划,时间复杂度是O(n^2):改进的方法时间复杂度 ...

  5. 最长递增子序列LIS再谈

    DP模型: d(i) 以第 i 个元素结尾的最长递增子序列的长度. 那么就有 d(i) = max(d(j)) + 1;(j<i&&a[j]<a[i]),答案 max(d( ...

  6. 动态规划 - 最长递增子序列LIS

    问题:一个序列有N个数:A[1],A[2],-,A[N],求出最长非降子序列的长度 样例输入:3 1 2 6 5 4 思路: 首先把问题简单化.可以先求A[1],...A[i]的最长非降子序列,令dp ...

  7. 编程之美-求数组中最长递增子序列(LIS)方法整理

    [试题描述] 方法一:时间复杂度O(n^2) 方法二:时间复杂度O(n^2) 方法三: 修改方法二中的穷举搜索部分为如下: 如果把上述查询部分利用二分搜索进行加速,可以得到时间复杂度为O(nlogn) ...

  8. 数组字符串那些经典算法:最大子序列和,最长递增子序列,最长公共子串,最长公共子序列,字符串编辑距离,最长不重复子串,最长回文子串 (转)...

    作者:寒小阳 时间:2013年9月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/11969497. 声明:版权所有,转载请注明出处,谢谢 ...

  9. 51nod1134最长递增子序列(dp)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1134 这里说下,最长上升子序列和最长不降子序列几乎一样,只是判 ...

最新文章

  1. 【C++】decltype作用探究,unsigned与signed混淆问题
  2. web前段学习day_01:HTML(学习如何搭建页面结构和内容):文本标签、列表标签、图片标签、超链接、表格、表单表单、分区标签、实体引用
  3. Android Low Battery 低电量处理流程
  4. Linux下解决高并发socket最大连接数限制,tcp默认1024个连接
  5. collatz序列 python程序_Python Collatz序列实现过程解析
  6. SBCL 使用中文时的错误记录 --close 问题已经解决
  7. 用批处理开启或关闭windows 服务
  8. 刚接手的项目代码 怎么看_你们刚开始是怎么看英文文献的?
  9. PowerDesigner建立数据库模型
  10. 什么是云计算云计算能干什么?云计算学习笔记工具素材
  11. 问题:混合现实门户,三星玄龙MR检测不到设备
  12. 捋一捋DDR内存相关的各种频率
  13. ONF解决方案与合作伙伴副主席Aseem Parikh:CORD的社区增长概况及全球发展趋势
  14. 用不可描述的图片做可以描述的事情
  15. 共享经济突围路在何方 ?共享洗衣机能否突围?
  16. Linux下scp的用法
  17. UOS 开启开发者选项并激活系统
  18. 《混乱的猴子》读书笔记 -- 关于硅谷、创业、Facebook和广告
  19. 开发一个基于 Android系统车载智能APP
  20. 使用minio进行文件存储

热门文章

  1. Pytorch:卷积神经网络-GoogLeNet
  2. selenium | firefox代理设置
  3. 复杂网络入门详解 适用于初学者。超详细~~
  4. 计算机如何打开无线网络适配器,网络适配器无法启动如何解决?解决方法步骤...
  5. 应届毕业生的前端“干货”(一)
  6. 解密区块链中的密码学
  7. 与计算机互动大学英语,【2017年整理】基于与网络和计算机的大学英语教学模式.ppt...
  8. 计蒜客 Emptying the Baltic (BFS+Dijkstra)
  9. 面试官:为什么 Kafka 如此之快?
  10. 砸金蛋抽奖php源码,砸金蛋 抽奖 游戏 完整源码下载 有截图