题目 算法
A、AcWing 895. 最长上升子序列 模板
B、AcWing1017. 怪盗基德的滑翔翼 最长上升子序列/最长下降子序列
C、AcWing 1014. 登山 最长上升子序列/最长下降子序列
D、AcWing 482. 合唱队形 最长上升子序列
E、AcWing 1012. 友好城市 思维
F、AcWing 1016. 最大上升子序列和 DP递推

目录

  • A、AcWing 895. 最长上升子序列(模板)
  • B、AcWing1017. 怪盗基德的滑翔翼 (最长上升子序列/最长下降子序列)
  • C、AcWing 1014. 登山 (最长上升子序列/最长下降子序列)
  • D、AcWing 482. 合唱队形
  • E、AcWing 1012. 友好城市
  • F、AcWing 1016. 最大上升子序列和

A、AcWing 895. 最长上升子序列(模板)

给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。

今天的最长上升子序列模型的基础

这里是一个O(n2)O(n^ 2)O(n2)的做法。可以用二分优化成O(nlogn)O(nlogn)O(nlogn)

#include <iostream>
#include <algorithm>
#include <cstdio>using namespace std;const int N = 50007, M = 500007, INF = 0x3f3f3f3f;int n,m;
int a[N], f[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i){scanf("%d",&a[i]);}for(int i = 1;i <= n;++i){f[i] = 1;for(int j = 1;j < i;++j)if(a[j] < a[i])f[i] = max(f[i], f[j] + 1);}int res = 0;for(int i = 1;i <= n;++i)res = max(res,f[i]);printf("%d\n",res);return 0;
}

二分优化的O(nlogn)O(nlogn)O(nlogn)
这里直接是拦截导弹的代码,求的是最长不上升子序列(d1,<=)和最长上升子序列(d2, >)
大体的思路就是数组维护一个伪单调栈,每次新的元素如果满足单调性就加入,如果不满足单调性就替换到满足的那一位置,前面的并不删除,只是替换,所以是伪单调栈,最后求最大值即可(主要是替换之后当前的答案也不会改变,但是利用了一个贪心的思想,换完之后可能会更优。因为同样是这么多,我们选更低的肯定后面选择空间会更大,比如当前最大值为300,后面还有两个数,200和250,如果我们到200的时候替换了(此时答案不变),把300替换成200,最后的250就可以取了,答案最优,不然的话250就取不了了)

贴一个解析

#include<iostream>
#include<cstdio>
#include<algorithm>
#define R register
using namespace std;
const int N=100010;
int a[N],d1[N],d2[N],n;
inline bool read(int &x) {char c=getchar();if(c==EOF)return false;while(c>'9'||c<'0')c=getchar();while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}return true;
}
int main() {while(read(a[++n]));n--;R int len1=1,len2=1;d1[1]=d2[1]=a[1];for(R int i=2; i<=n; i++) {//最长不升子序列if(d1[len1]>=a[i])d1[++len1]=a[i];else *upper_bound(d1+1,d1+1+len1,a[i],greater<int>())=a[i];//最长上升子序列if(d2[len2]<a[i])d2[++len2]=a[i];else *lower_bound(d2+1,d2+1+len2,a[i])=a[i];}printf("%d\n%d",len1,len2);return 0;
}

B、AcWing1017. 怪盗基德的滑翔翼 (最长上升子序列/最长下降子序列)



因为有两种方向,所以我们正向跑一次lcs,逆向跑一次lcs(最长下降子序列),求最大值即可。

#include<iostream>
#include<cstdio>
#include<algorithm>using namespace std;const int N = 500, M = 50007, INF = 0x3f3f3f3f;int n, m;
int t;
int a[N], f[N], g[N];int main(){scanf("%d",&t);while(t -- ){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(int i = 1;i <= n;++ i){f[i] = 1;for(int j = 1;j < i;++j)if(a[j] < a[i])f[i] = max(f[i], f[j] + 1);}for(int i = n;i >= 1;-- i){g[i] = 1;for(int j = n;j > i;--j)if(a[j] < a[i])g[i] = max(g[i],g[j] + 1);}int res = 0;for(int i = 1;i <= n;++i)res = max(res,max(f[i],g[i]));printf("%d\n",res);}return 0;
}

C、AcWing 1014. 登山 (最长上升子序列/最长下降子序列)


本题实际上是求一个最大上升子序列到一个点,然后再以该点为起点求一个最长下降子序列。所以我们可以先预处理出正向的最长上升子序列,再求一个逆向的最长上升子序列(就是最长下降子序列),然后枚举每一个点作为起点,求一个最大值。要注意的是枚举的这个起点被两个子序列算了两次,所以要-1。

#include<iostream>
#include<cstdio>
#include<algorithm>using namespace std;const int N = 1010, M = 50007, INF = 0x3f3f3f3f;int n, m;
int t;
int a[N], f[N], g[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(int i = 1;i <= n;++ i){f[i] = 1;for(int j = 1;j < i;++j)if(a[j] < a[i])f[i] = max(f[i], f[j] + 1);}for(int i = n;i >= 1;-- i){g[i] = 1;for(int j = n;j > i;--j)if(a[j] < a[i])g[i] = max(g[i],g[j] + 1);}int res = 0;for(int i = 1;i <= n;++i)res = max(res, f[i] + g[i] - 1);printf("%d\n",res);return 0;
}

D、AcWing 482. 合唱队形


这题和上一道登山几乎一摸一样,只不过求的答案是踢走多少人,所以是n-res

const int N = 1010, M = 50007, INF = 0x3f3f3f3f;
int n, m;
int t;
int a[N], f[N], g[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(int i = 1;i <= n;++ i){f[i] = 1;for(int j = 1;j < i;++j)if(a[j] < a[i])f[i] = max(f[i], f[j] + 1);}for(int i = n;i >= 1;-- i){g[i] = 1;for(int j = n;j > i;--j)if(a[j] < a[i])g[i] = max(g[i],g[j] + 1);}int res = 0;for(int i = 1;i <= n;++i)res = max(res, f[i] + g[i] - 1);printf("%d\n",n - res);return 0;
}

E、AcWing 1012. 友好城市


当i>ji>ji>j且i友>j友i_{友}>j_友i友​>j友​时不交叉

所以可以将南岸从小到大排序 求北岸的最长上升子序列

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>using namespace std;const int N = 5000007, M = 5000007, INF = 0x3f3f3f3f;
typedef pair<int,int> PII;
int n, m;
int b[N];
int f[N];
PII a[N];
int len = 1;
int main(){scanf("%d",&n);for(int i = 1;i <= n;++i){scanf("%d%d",&a[i].first, &a[i].second);}sort(a + 1,a + 1 + n);f[1] = a[1].second;for(int i = 2;i <= n;++i){if(f[len] < a[i].second)f[++len] = a[i].second;else {//int tmp = lower_bound(f + 1, f + 1 + len, a[i].second) - f;//f[tmp] = a[i].second;*lower_bound(f + 1 ,f + 1 + len,a[i].second) = a[i].second;}}printf("%d\n",len);return 0;
}

F、AcWing 1016. 最大上升子序列和



DP问题注意初始化,这里要初始化f[i] = a[i];很关键。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 5007, INF = 0x3f3f3f3f;int n, m;
int a[N], f[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(int i = 1;i <= n;++i){f[i] = a[i];for(int j = 1;j < i;++j)if(a[j] < a[i])f[i] = max(f[i],f[j] + a[i]);}int res = 0;for(int i = 1;i <= n;++i)res = max(res,f[i]);printf("%d\n",res);return 0;}

【动态规划专题】最长上升子序列模型相关推荐

  1. ACwing 895 - 最长上升子序列(最长上升子序列模型)

    给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少. 输入格式 第一行包含整数N. 第二行包含N个整数,表示完整序列. 输出格式 输出一个整数,表示最大长度. 数据范围 1 ≤ N ≤ ...

  2. [AcWing] 1012. 友好城市(C++实现)最长上升子序列模型、较为特殊

    [AcWing] 1012. 友好城市(C++实现)最长上升子序列模型 1. 题目 2. 读题(需要重点注意的东西) 3. 解法 4. 可能有帮助的前置习题 5. 所用到的数据结构与算法思想 6. 总 ...

  3. 动态规划解决最长公共子序列

    动态规划解决最长公共子序列 问题描述 给定两个序列,例如 X = "ABCBDAB".Y = "BDCABA",求它们的最长公共子序列的长度. 递归关系 c[i ...

  4. C++动态规划之最长上升子序列

    1 子序列与上升子序列 1.1 子序列 一个序列A={a1,a2,...an}中任意删除若干项,剩余的序列叫做A的一个子序列.例如序列A={1,3,5,4,2},删除其中的第3项和第5项,得到序列B= ...

  5. 动态规划解最长公共子序列(LCS)(附详细填表过程)

    目录 相关概念 子序列形式化定义: 公共子序列定义: 最长公共子序列(以下简称LCS): 方法 蛮力法求解最长公共子序列: 动态规划求解最长公共子序列: 分析规律: 做法: 伪代码: 下面演示下c数组 ...

  6. javascript写算法(一) 动态规划:最长公共子序列

    csdn是疯了吗,右下角的广告是一个人站在猪屁股后面打它...看了一下居然是baidu算出来的广告嵌在了iframe里,fixed to viewport,真是够了.最近还频频出现的广告是一个光头男子 ...

  7. 最长上升子序列模型 AcWing 1010. 拦截导弹

    最长上升子序列模型 AcWing 1010. 拦截导弹 原题链接 AcWing 1010. 拦截导弹 算法标签 DP 线性DP 最长上升子序列 思路 摘自该题解 代码 #include<bits ...

  8. C++---最长上升子序列模型---导弹防御系统(每日一道算法2023.3.5)

    注意事项: 本题的dp:"线性dp-最长上升子序列的长度" 本题的贪心(单调队列):"最长上升子序列模型-拦截导弹" 下面思路只讲如何运用这些东西来解这道题 强 ...

  9. 动态规划——最长上升子序列模型

    最长上升子序列 给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少. 输入格式 第一行包含整数 N. 第二行包含 N 个整数,表示完整序列. 输出格式 输出一个整数,表示最大长度. ...

最新文章

  1. Okhttp 使用与debug时留的大坑
  2. Vue入门一、常用的指令
  3. DPDK — DPDK APP 的指令行参数
  4. 我非要捅穿这 Neutron(四)Open vSwitch in Neutron
  5. Linux应用总结(1):自动删除n天前日志
  6. 【Flutter】Flutter 混合开发 ( Flutter 与 Native 通信 | 在 Flutter 端实现 MethodChannel 通信 )
  7. Non-interger Area 分类讨论 奇偶 取模 牛客练习赛95
  8. 5918. 统计字符串中的元音子字符串
  9. 评论:电商巨头们谁有勇气晒晒“价格战”账单?
  10. LintCode解题目录
  11. python文件路径改了需要重新配置环境吗_python自学环境配置
  12. 老子《道德经》第三章
  13. 在OpenSSL中添加自定义加密算法
  14. ADB登录验证暴力破解工具
  15. 热门的Linux运维管理面板全面汇总
  16. 扫描域名和扫描IP的区别
  17. rust服务器显示长度,rust服务器设置倍率
  18. 百度AI市场MYNT EYE小觅双目摄像机开箱试用全记录
  19. Altium Designer禁止联网操作说明
  20. 浅谈几款软件的创新点

热门文章

  1. L-SNET:从区域定位到尺度不变的医学图像分割
  2. 2018-2019-1 20165318 20165322 20165326 实验四 外设驱动程序设计
  3. 4 Git 基础 - 撤消操作
  4. 正则表达式、事件调用
  5. MySQL数据库MyISAM存储引擎转为Innodb
  6. RHCS创建高可用性群集Apache服务器
  7. javax/management/DynamicMBean
  8. sar分辨率公式_初识合成孔径雷达SAR
  9. 汇编语言w3c_w3cschoolc语言教程
  10. python判断密码是否正确_第一个python程序-判断登陆用户名和密码是否正确