|
|
|
@ -597,7 +597,7 @@ int main() {
|
|
|
|
|
int mx = 1; // 最起码a[i]==b[j],有一个数字是一样嘀~
|
|
|
|
|
// f[i-1]是肯定的了,问题是b的前驱在哪里?需要枚举1~j-1
|
|
|
|
|
for (int k = 1; k < j; k++)
|
|
|
|
|
if (b[j] > b[k]) // j可以接在k后面,那么可能的最大值为f[i-1][k]+1
|
|
|
|
|
if (a[i] > b[k]) // j可以接在k后面,那么可能的最大值为f[i-1][k]+1
|
|
|
|
|
mx = max(mx, f[i - 1][k] + 1);
|
|
|
|
|
// 更新答案
|
|
|
|
|
f[i][j] = max(f[i][j], mx);
|
|
|
|
@ -610,8 +610,12 @@ int main() {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
前面之所以把$b[j]$换成$a[i]$,是因为方便现在考虑。
|
|
|
|
|
|
|
|
|
|
由于在枚举计算$f[i][j]$时,却用到的是和内层循环(即$b[j]$)无关的,只和外层循环(即$a[i]$)有关,而我们在计算$f[i][j]$,每次都要用到前$j−1$个数中小于$a[i]$的$f[i-1][k]$最大值,所以我们可以用一个变量$mx$不断更新它来保存前$j−1$的答案,就可以避免重复计算,从而降低时间复杂度。
|
|
|
|
|
|
|
|
|
|
$O(N^2)$
|
|
|
|
|
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
|
|
#include <bits/stdc++.h>
|
|
|
|
|
|
|
|
|
@ -622,6 +626,7 @@ int f[N][N];
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
// O(n^2)
|
|
|
|
|
// f[i][j]—集合:考虑 a 中前 i 个数字,b 中前 j 个数字 ,且当前以 b[j] 结尾的子序列的方案
|
|
|
|
|
int main() {
|
|
|
|
|
int n;
|
|
|
|
|
cin >> n;
|
|
|
|
@ -629,10 +634,9 @@ int main() {
|
|
|
|
|
for (int i = 1; i <= n; i++) cin >> b[i];
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i <= n; i++) {
|
|
|
|
|
int mx = 1; // 将mx提到二层循环的外面,因为O(n^3)之所以慢,就是因为存在重复计算,每次都需要从头找一遍可以接在后面的同时上升序列最长的那个k
|
|
|
|
|
// 由于循环从左到右进行时,每次这个mx是可以记录下来,下次不用重复计算的,所以,可以复用
|
|
|
|
|
int mx = 1; // 如果a[i]==b[j],那么LICS最小是1.如果下面的循环中没有一个if被执行,则mx没使上
|
|
|
|
|
for (int j = 1; j <= n; j++) {
|
|
|
|
|
f[i][j] = f[i - 1][j];
|
|
|
|
|
f[i][j] = f[i - 1][j]; // 先继承过来,现实含义:即使a[i]!=b[j],那么最长长度不会因为i的增加而变化,即f[i][j]=f[i-1][j]
|
|
|
|
|
if (a[i] == b[j]) f[i][j] = mx;
|
|
|
|
|
if (a[i] > b[j]) mx = max(mx, f[i - 1][j] + 1);
|
|
|
|
|
}
|
|
|
|
@ -643,6 +647,5 @@ int main() {
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
[最长上升子序列 ($LIS$) 详解+例题模板 (全)](https://blog.csdn.net/lxt_Lucia/article/details/81206439)
|
|
|
|
|