AcWing 482. 合唱队形(Java 正序、逆序两段最长上升子序列)
原题链接
中等
作者:
Limited
,
2021-02-17 22:33:26
,
所有人可见
,
阅读 361
思路
- 符合题意的正确序列应是呈先上升再下降,则中间必有一个点既是前一段上升序列的终点,也是后一段下降序列的起点
- 因为DP求的是以XX为末尾的长度,而本题下降序列已知起点、终点不定,所以将下降序列视作逆序的上升序列,则终点与前半段上升序列一致
- 因为两段终点一致,在计算总长度时,两段序列长度相加还要再减去重复终点的1
- 枚举所有点作为终点的情况,求的最长的总序列
代码
import java.util.*;
import java.lang.*;
public class Main {
static Scanner scanner = new Scanner(System.in);
static int n;
static int[] f = new int[110], g = new int[110], a = new int[110];
public static void main(String[] args) {
n = scanner.nextInt();
for (int i = 1; i <= n; i++) {
a[i] = scanner.nextInt();
}
for (int i = 1; i <= n; i++) { // 求正序的最长上升子序列长度
f[i] = 1;
for (int j = 1; j < i; j++) {
if (a[j] < a[i]) {
f[i] = Math.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] = Math.max(g[i], g[j] + 1);
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++) { // 枚举所有点作为终点的情况 求先↑后↓序列的长
ans = Math.max(ans, f[i] + g[i] - 1);
}
System.out.println(n - ans); // 总人数-序列长=待剔除的人数
}
}