From ae6bce7770097ba7fe1871fb1a0225cfc320be2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Tue, 5 Mar 2024 16:42:56 +0800 Subject: [PATCH] 'commit' --- TangDou/AcWing_TiGao/T1/LIS/897.cpp | 6 +- TangDou/AcWing_TiGao/T1/LIS/897.md | 8 +- TangDou/AcWing_TiGao/T1/LIS/LIS+LCS专题.md | 94 ++++++++++++++++++- .../T1/LIS/最长上升子序列专题.md | 2 - 4 files changed, 98 insertions(+), 12 deletions(-) delete mode 100644 TangDou/AcWing_TiGao/T1/LIS/最长上升子序列专题.md diff --git a/TangDou/AcWing_TiGao/T1/LIS/897.cpp b/TangDou/AcWing_TiGao/T1/LIS/897.cpp index cc2bc9c..e0d49fa 100644 --- a/TangDou/AcWing_TiGao/T1/LIS/897.cpp +++ b/TangDou/AcWing_TiGao/T1/LIS/897.cpp @@ -11,8 +11,10 @@ int main() { cin >> n >> m >> a + 1 >> b + 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { - f[i][j] = max(f[i - 1][j], f[i][j - 1]); - if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1; + if (a[i] == b[j]) + f[i][j] = f[i - 1][j - 1] + 1; + else + f[i][j] = max(f[i - 1][j], f[i][j - 1]); } printf("%d", f[n][m]); return 0; diff --git a/TangDou/AcWing_TiGao/T1/LIS/897.md b/TangDou/AcWing_TiGao/T1/LIS/897.md index 4f6555e..c300746 100644 --- a/TangDou/AcWing_TiGao/T1/LIS/897.md +++ b/TangDou/AcWing_TiGao/T1/LIS/897.md @@ -39,7 +39,6 @@ abedc * 当$a[i] \neq b[j]$时: * 如果$a[i]$不产生贡献,那么把它干掉$f[i-1][j]$ * 如果$b[j]$不产生贡献,那么把它干掉$f[i][j-1]$ - * 如果两个都没有贡献,那么就是$f[i-1][j-1]$ ![](https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/BlogImages/202403041643972.png) @@ -59,11 +58,12 @@ int main() { cin >> n >> m >> a + 1 >> b + 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { - f[i][j] = max(f[i - 1][j], f[i][j - 1]); - if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1; + if (a[i] == b[j]) + f[i][j] = f[i - 1][j - 1] + 1; + else + f[i][j] = max(f[i - 1][j], f[i][j - 1]); } printf("%d", f[n][m]); return 0; } - ``` diff --git a/TangDou/AcWing_TiGao/T1/LIS/LIS+LCS专题.md b/TangDou/AcWing_TiGao/T1/LIS/LIS+LCS专题.md index 26eb28d..331b61f 100644 --- a/TangDou/AcWing_TiGao/T1/LIS/LIS+LCS专题.md +++ b/TangDou/AcWing_TiGao/T1/LIS/LIS+LCS专题.md @@ -1,10 +1,94 @@ ## $LIS$+$LCS$专题 #### 基础题 -[AcWing 895. 最长上升子序列](https://www.acwing.com/problem/content/897/) -[AcWing 896. 最长上升子序列 II ](https://www.acwing.com/problem/content/898/) -[AcWing 897. 最长公共子序列](https://www.acwing.com/problem/content/899/) +**[$AcWing$ $895$. 最长上升子序列](https://www.acwing.com/problem/content/897/)** +$O(N^2)$算法 + +**状态表示** +$f[i]$:以$a[i]$结尾的最长上升子序列长度 + +**状态转移** +```cpp {.line-numbers} + for (int i = 1; i <= n; i++) { + f[i] = 1; //只有a[i]一个数 + for (int j = 1; j < i; j++) + if (a[j] < a[i]) f[i] = max(f[i], f[j] + 1); + } +``` +**答案** +```cpp {.line-numbers} +for (int i = 1; i <= n; i++) res = max(res, f[i]); +``` + + +**[$AcWing$ $896$. 最长上升子序列 II ](https://www.acwing.com/problem/content/898/)** + +数据量增大:$N<=100000$ +$O(LogN*N)$算法 + +```cpp {.line-numbers} + // 1、首个元素入栈 +f[0] = a[0]; + +// 2、后续元素开始计算 +for (int i = 1; i < n; i++) { + if (a[i] > f[fl]) + f[++fl] = a[i]; + else + //利用STL的二分,在f中查找第一个大于等于a[i]的值,并完成替换 + *lower_bound(f, f + fl, a[i]) = a[i]; +} +``` + +也可以这样写 +```cpp {.line-numbers} +memset(f,-0x3f,sizeof f); + +// 2、后续元素开始计算 +for (int i = 1; i <= n; i++) { + if (a[i] > f[fl]) + f[++fl] = a[i]; + else + //利用STL的二分,在f中查找第一个大于等于a[i]的值,并完成替换 + *lower_bound(f + 1, f + 1 + fl, a[i]) = a[i]; +} +``` + +很明显,第一种写法性能更高,第二种写法有点暴力。 + +**状态表示** +$f[i]$表示长度为$i$的递增子序列中,末尾元素最小的是$f[i]$ + +**答案** +$fl$ + +**状态转移** +① $f[]$数组是一个单独上升的数组,这是可以二分的基础 +② 每个长度都争取替换掉前面记录数组中第一个大于等于自己的数字,以保证长度不变的情况下,数字最小,因为只有最小才能让后面的其它数字更容易接上去,机会才能更多。 + +**[$AcWing$ $897$. 最长公共子序列](https://www.acwing.com/problem/content/899/)** + +**状态表示** +定义$f[i][j]$是$a[]$以$i$结尾,$b[]$以$j$结尾的**最长公共子序列长度** +> **说明**:没有说$a[i]$或者$b[j]$一定要出现在最长公共子序列当中!这个最长公共子序列,可能是$a[]$和$b[]$的一些前序组成的,$a[i],b[j]$也可能没有对结果产生贡献。 + +* 当$a[i]==b[j]$时,看一下两个字符串的前序,发现在少了$a[i],b[j]$后,转化为子问题$f[i-1][j-1]$,问题转化为$$f[i][j]=f[i-1][j-1]+1$$ + +* 当$a[i] \neq b[j]$时: + * 如果$a[i]$不产生贡献,那么把它干掉$f[i-1][j]$ + * 如果$b[j]$不产生贡献,那么把它干掉$f[i][j-1]$ +```cpp {.line-numbers} +for (int i = 1; i <= n; i++) + for (int j = 1; j <= m; j++) { + if (a[i] == b[j]) + f[i][j] = f[i - 1][j - 1] + 1; + else + f[i][j] = max(f[i - 1][j], f[i][j - 1]); + } +``` +**答案** +$f[n][m]$ #### 进阶题 AcWing 1017. 怪盗基德的滑翔翼 @@ -14,4 +98,6 @@ AcWing 1012. 友好城市 AcWing 1016. 最大上升子序列和 AcWing 1010. 拦截导弹 AcWing 187. 导弹防御系统 -AcWing 272. 最长公共上升子序列 \ No newline at end of file +AcWing 272. 最长公共上升子序列 + +[最长上升子序列 ($LIS$) 详解+例题模板 (全)](https://blog.csdn.net/lxt_Lucia/article/details/81206439) diff --git a/TangDou/AcWing_TiGao/T1/LIS/最长上升子序列专题.md b/TangDou/AcWing_TiGao/T1/LIS/最长上升子序列专题.md deleted file mode 100644 index d32212e..0000000 --- a/TangDou/AcWing_TiGao/T1/LIS/最长上升子序列专题.md +++ /dev/null @@ -1,2 +0,0 @@ -### 五、相关资源 -[最长上升子序列 ($LIS$) 详解+例题模板 (全)](https://blog.csdn.net/lxt_Lucia/article/details/81206439)