BEGIN


LIS:

一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

输入样例 7

     2 5 3 4 1 7 6

输出样例 4

1.上升序列: //???这里怎么格式这么丑,还调不了

这道题中就是在当前序列删去几个数,使剩下的几个数构成一个从小到大的序列,例如:2 3 4 6和2 4 7都是上升序列.

2.具体思路:

设定一个一维数组f[i],表示从1到i的最大上升子序列长度,所以f数组中的每一个数都应该初始化为1,因为一个数本身的长度就是1,我们可以让原数组a中的每一个数依次与它前面的所有数进行比较,如果当前的a[i]>a[j]且当前的f[i]大于f[j],那么我们的f[i]就可以从f[j]转移过来,新得到的f[i]就是f[j]的大小加上1,于是我们就得到了我们动归中的第一个转移方程:f[i]=max(f[j]+1)(i>j&&a[i]>a[j]),时间效率:O(n*n)

3.主代码:

  1. for(int i=;i<=n;i++){
  2. for(int j=;j<i;j++){//j严格小于i,否则可能会WA
  3. if(a[i]>a[j]&&f[i]<f[j]+){//一般比较时要写的是f[i]<f[j]+1而不是f[i]<=f[j]
  4. f[i]=f[j]+;
  5. dp[i]=j;//记录路径的,下面会说路径输出
  6. ans=max(ans,f[i]);
  7. }
  8. }
  9. }

4.优化://正常人用二分优化,不正常的人用树形优化,用树形优化的估计也用指针建树

对于一个上升子序列,其结尾元素越小肯定以后能插入的元素越多,子序列的长度也就越大,这里我们抛弃数组f,新建一个数组low,low[i]表示长度为i的LIS结尾元素的最小值。对于一个新的数,如果这个数比当前序列末尾元素要大,那肯定是要插在队尾,如果不大于的话,就需要找到low数组中第一个大于这个数的位置并替换掉,如此一来就能够插入尽量多的元素,而时间效率为O(n*logn),如图:

代码如下:

  1. low1[]=a[];//长度为1的序列最后一个元素一开始肯定是原序列的第一个数
  2. for(int i=;i<=n;i++){
  3. if(low1[ans1]<a[i])low1[++ans1]=a[i];
  4. else low1[lower_bound(low1+,ans1++low1,a[i])-low1]=a[i];
  5. }//low_bound函数可以帮助我们快速找到第一个大于某数的位置
  6. //而upper_bound可以帮助我们快速找到第一个大于等于某数的位置
  7. //原理都是二分,用法如代码中的那样

5.路径记录:懒得写了,等以后有时间再写

6.友情例题链接:友好城市:https://www.cnblogs.com/614685877--aakennes/p/12659005.html

        导弹拦截:没写

        打地鼠:没写


LCS:

子序列:一个序列A = a1,a2,……an,中任意删除若干项,剩余的序列叫做A的一个子序列。也可以认为是从序列A按原顺序保留任意若干项得到的序列。

公共子序列:顾名思义,如果序列C既是序列A的子序列,同时也是序列B的子序列,则称它为序列A和序列B的公共子序列。空序列是任何两个序列的公共子序列。

最长公共子序列:A和B的公共子序列中长度最长的(包含元素最多的)叫做A和B的公共子序列。

输入样例:8 6

     1 3 5 4 2 6 8 7

     1 4 8 6 7 5

输出样例:4

hint:最长公共子序列有两个分别是: 1 4 8 7 ,1 4 6 7

1.如果暴力枚举,把两个序列中的数都扫一遍,序列一有2n个子序列,序列二有2m个子序列,时间效率为O(2^(m+n)).

2.定义二维数组f,f[i][j]变数为序列1前i个数,序列2中前j个数的LCS,如图所示f[i][j]如果a[i]!=a[j],那么f[i][j]会从它上一个或左一个中的最大值直接转移,如果a[i]==a[j]那么它会从左上角转移过来,值为f[i-1][j-1]+1(应该没人会问为什么不是从上或从下转移的吧,实在不懂就看图)


时间:4.9夜里11点,溜了溜了


时间:4.11早上19丶 

在多科积累本的压榨下,终于抽出时间来更新了(其实有没写完的,明天再说)


3.状态转移方程:f[i][j]=max(f[i-1][j],f[i][j-1])(a[i]!=a[j]) f[i][j]=f[i-1][j-1]+1(a[i]==a[j])

4.代码:

未优化:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<stack>
  7. using namespace std;
  8. const int maxn=1e3+,INF=0x3f3f3f3f;
  9. int n,len1,len2,f[maxn][maxn],a1[maxn],a2[maxn];
  10. int main(){
  11. freopen("a.in","r",stdin);
  12. cin>>len1>>len2;
  13. for(int i=;i<=len1;i++)cin>>a1[i];
  14. for(int i=;i<=len2;i++)cin>>a2[i];
  15. int ans=;
  16. for(int i=;i<=len1;i++){
  17. for(int j=;j<=len2;j++){
  18. if(a1[i]==a2[j])f[i][j]=f[i-][j-]+;
  19. else if(a1[i]!=a2[j])f[i][j]=max(f[i-][j],f[i][j-]);
  20. ans=max(ans,f[i][j]);
  21. }
  22. }
  23. cout<<ans;
  24. return ;
  25. }

滚动数组优化版本:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<stack>
  7. using namespace std;
  8. const int maxn=1e3+,INF=0x3f3f3f3f;
  9. int n,len1,len2,f[maxn][maxn],a1[maxn],a2[maxn];
  10. int main(){
  11. freopen("a.in","r",stdin);
  12. cin>>len1>>len2;
  13. for(int i=;i<=len1;i++)cin>>a1[i];
  14. for(int i=;i<=len2;i++)cin>>a2[i];
  15. int ans=,k=;
  16. for(int i=;i<=len1;i++){
  17. k=!k;
  18. for(int j=;j<=len2;j++){
  19. if(a1[i]==a2[j])f[k][j]=f[!k][j-]+;//正常滚动数组,用i%2也行
  20. else if(a1[i]!=a2[j])f[k][j]=max(f[!k][j],f[k][j-]);
  21. ans=max(ans,f[k][j]);
  22. }
  23. }
  24. cout<<ans;
  25. return ;
  26. }

5.路径记录

回看之前那张图,褐色的正好是其种的一种序列,都是从左上转移过来,所以我们只需开一个二维数组记录下转移状态,然后递归输出即可(其实也可以用滚动数组优化)

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<stack>
  7. using namespace std;
  8. const int maxn=1e3+,INF=0x3f3f3f3f;
  9. int n,len1,g[maxn][maxn],len2,f[maxn][maxn],a1[maxn],a2[maxn];
  10. void Print(int i,int j){
  11. if(i==||j==)return;
  12. if(g[i][j]==)Print(i-,j-),cout<<a1[i]<<" ";
  13. if(g[i][j]==)Print(i-,j);
  14. if(g[i][j]==-)Print(i,j-);
  15. }
  16. int main(){
  17. freopen("a.in","r",stdin);
  18. cin>>len1>>len2;
  19. for(int i=;i<=len1;i++)cin>>a1[i];
  20. for(int i=;i<=len2;i++)cin>>a2[i];
  21. int ans=,k=;
  22. for(int i=;i<=len1;i++){
  23. //滚动数组大变样 
  24. for(int j=;j<=len2;j++){
  25. if(a1[i]==a2[j])f[i%][j]=f[(i-)%][j-]+,g[i][j]=;//0表示左上 
  26. else if(f[i-][j]>=f[i%][j-])f[i%][j]=f[(i-)%][j],g[i][j]=;//1表示正上
  27. else f[i%][j]=f[i%][j-],g[i][j]=-;//-1表示正左 
  28. ans=max(ans,f[k][j]);
  29. }
  30. }
  31. cout<<ans;
  32. return ;
  33. }//嘤嘤嘤,编译过了,但不保证A

6.友情例题链接:Prince and Princess 王子和公主:https://www.cnblogs.com/614685877--aakennes/p/12663440.html

LCIS:

两个整数序列,{a1,a2...,am},{b1,b2...,bn},求两序列最长公共上升子序列长度。

//怎么粘贴过来变成图片了?

1.LCIS显然是LIS和LCS的并查集,不对,是交集(并查集题做多了),定义二维数组f,f[i][j]表示第一个序列前i个元素,第二个序列前j个元素且以b[j]结束的LCIS,两个序列最后的元素为a[i]、b[j]。如果a[i]!=b[j],f[i][j]=f[i-1][j],因为此时以b[j]结尾的LCIS有没有a[i]结果是一样的;相反,如果a[i]==b[j],此时f[i][j]=max(f[i-1][k])+1。(从老师那里搬过来的课件有丶混乱,还是代码好理解丶)

2.代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<stack>
  7. using namespace std;
  8. const int maxn=1e3+,INF=0x3f3f3f3f;
  9. int n,len1,g[maxn][maxn],len2,f[maxn][maxn],a1[maxn],a2[maxn];
  10. int main(){
  11. freopen("a.in","r",stdin);
  12. cin>>len1>>len2;
  13. for(int i=;i<=len1;i++)cin>>a1[i];
  14. for(int i=;i<=len2;i++)cin>>a2[i];
  15. int ans=,k=;
  16. for(int i=;i<=len1;i++){
  17. ans=;
  18. for(int j=;j<=len2;j++){
  19. if(a[i]>b[j]&&ans<f[j])ans=f[j];
  20. if(a[i]==b[j])f[j]=ans+;
  21. }
  22. }
  23. cout<<ans;
  24. return ;
  25. }//嘤嘤嘤

终于写完了,写了两三个小时

【线型DP模板】最上上升子序列(LIS),最长公共子序列(LCS),最长公共上升子序列(LCIS)的更多相关文章

  1. 最长上升子序列 LIS(Longest Increasing Subsequence)

    引出: 问题描述:给出一个序列a1,a2,a3,a4,a5,a6,a7….an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质,s1<s2<s3<…< ...

  2. 动态规划——最长上升子序列LIS及模板

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

  3. 动态规划(DP),最长递增子序列(LIS)

    题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...

  4. 1. 线性DP 300. 最长上升子序列 (LIS)

    最经典单串: 300. 最长上升子序列 (LIS) https://leetcode-cn.com/problems/longest-increasing-subsequence/submission ...

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

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

  6. 算法之动态规划(最长递增子序列——LIS)

    最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...

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

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

  8. 【部分转载】:【lower_bound、upperbound讲解、二分查找、最长上升子序列(LIS)、最长下降子序列模版】

    二分 lower_bound lower_bound()在一个区间内进行二分查找,返回第一个大于等于目标值的位置(地址) upper_bound upper_bound()与lower_bound() ...

  9. hdu----(1950)Bridging signals(最长递增子序列 (LIS) )

    Bridging signals Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

随机推荐

  1. 自己动手写SQL执行引擎

    自己动手写SQL执行引擎 前言 在阅读了大量关于数据库的资料后,笔者情不自禁产生了一个造数据库轮子的想法.来验证一下自己对于数据库底层原理的掌握是否牢靠.在笔者的github中给这个database起 ...

  2. 20行Python代码开发植物识别 app

    这篇文章介绍如何用Python快速实现一个植物识别的app,家里养了几盆多肉还叫不上名字,正好拿来识别一下.实现这样一个app只需要20行左右的代码,先来看下效果: 另外,我也开发了微信小程序版本,大 ...

  3. Netty 源码解析: Netty 的 ChannelPipeline

    ChannelPipeline和Inbound.Outbound         我想很多读者应该或多或少都有 Netty 中 pipeline 的概念.前面我们说了,使用 Netty 的时候,我们通 ...

  4. [AGC034F]RNG and XOR

    题目   点这里看题目. 分析   第一步可以将\(A\)数组转化成概率\(P(j)\):每一步操作异或\(j\)的概率.   接着发现,\(x\)从\(0\)变成\(i\)的期望等于\(x\)从\( ...

  5. Kubernetes-subpath的使用

    一.什么是subpath 为了支持单一个pod多次使用同一个volume而设计,subpath翻译过来是子路径的意思,如果是数据卷挂载在容器,指的是存储卷目录的子路径,如果是配置项configMap/ ...

  6. Navicat Premium 12安装激活教程_不需要激活工具直接激活

    问题场景:在使用注册机进行破解navicat的时候,在最后一步生成激活码的时候报错:Error on Decrypt Request Code…… 解决方案:1.先关闭Navicat2.Windows ...

  7. numpy.stack和numpy.concatenate的区别

    在使用numpy进行矩阵运算的时候踩到的坑,原因是不能正确区分numpy.concatenate和numpy.stack在功能上的差异. 先说numpy.concatenate,直接看文档: nump ...

  8. [apue] 一个快速确定新系统上各类限制值的工具

    对于在不同 Unix 系统之间移植程序,最重要的事情就是确定新系统的一些编译时.运行时固定或不固定的限制值了.例如文件路径最大长度 PATH_MAX.进程最大可打开文件句柄数 OPEN_MAX.用户可 ...

  9. Flutter学习笔记(35)--通知Notification

    如需转载,请注明出处:Flutter学习笔记(35)--通知Notification 通知的NotificationListener和我们之前写的事件的Listener一样,都是功能性的组件,而且也都 ...

  10. Error: Cannot find module 'webpack'

    运行 npm start 报错 Error: Cannot find module 'webpack' 安装了 npm install --save-dev webpack cnpm install ...