合唱队形 - 最长升序子序列的个数如何统计
一、题目描述:
n 位同学站成一排,音乐老师要请其中的 n-k 位同学出列,使得剩下的 k 位同学排成合唱队形。
合唱队形是指这样的一种队形:设 k 位同学从左到右依次编号为 1,2, … ,k,他们的身高分别为 t1,t2, … ,tk,则他们的身高满足 t1 < ⋯ < ti > ti+1 > … >tk (1≤i≤k)。
你的任务是,已知所有 n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
来源:洛谷 www.luogu.com.cn/problem/P10…
输入格式
共二行。
第一行是一个整数 n(2≤n≤100),表示同学的总数。
第二行有 n 个整数,用空格分隔,第 i 个整数 ti(130≤ti≤230)是第 i 位同学的身高(厘米)。
8
186 186 150 200 160 130 197 220
输出格式
一个整数,最少需要几位同学出列。
4
二、思路分析:
这道题目真的很巧妙(在我看来🤡),首先我们看懂题目,同学们的位置是不变的,只能有人退出去形成合唱队列,这个合唱队列是指以第 i 位同学开始向左看,身高是逐渐变矮的, 以第 i 位同学开始向右看,身高也是逐渐变矮的, 注意这个i位置可以是任何位置。 与我们生活中的合唱队列不一样,它不讲究对称的哈(我是憨批🤡)
我们按照左边从矮到高的开始排列最长升序列, 再从右边从矮到高的开始排列最长降序列,它们之间第 i 同学的位置就是它们之间的分界线。 所以我们只要看从 第1位 到 第i位同学 能按顺序排几个, 再加上从 第i+1位 到 第N位同学 能按顺序排几个,它们就能形成合唱队列
那我们怎么快速找到某个同学在升序/降序中排第几位呢,我们需要一个数组给它们的排列计数,这里的计数是一个递推,例如在升序排序中,第c位同学比第b位同学高,我们只需要看第b位同学在排序中排第几位,第c位同学+1位即可,这里第c位同学要和他前面所有同学进行比较,才能看最多能排到第几位
那我们一边看代码一边解释吧..
三、AC 代码:
import java.io.*;
public class Main {
// 输入流
static StreamTokenizer sr = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))) ;
public static void main(String[] args) {
int N = getInt() ;
int [] a = new int[N] ;
// 同学们的位置是不能动的,把它存起来
for( int i = 0 ; i < N ; i++ ) {
a[i] = getInt() ;
}
// s1 是从左到右升序 k 位置的同学能排第几个
int [] s1 = new int [N] ;
// s2 是从右到左升序 k 位置的同学能排第几个
int [] s2 = new int [N] ;
// 从左到右升序
for( int i = 0 ; i < N ; i++ ) {
int max = 1 ; // 从 i 同学开始排列,起码能站一个(它自己)
for( int j = 0 ; j < i ; j++ ) {
// 如果i前面的同学 j 比它小,它就可以排在j后面,它的位置就是s1[j]+1
if( a[i]>a[j] )
max = Math.max( s1[j]+1 , max ) ;
}
s1[i] = max ;
}
// 从右到左升序
for( int i = N-1 ; i >= 0 ; i-- ) {
int max = 1 ;
for( int j = N-1 ; j > i ; j-- ) {
if( a[i]>a[j] )
max = Math.max( s2[j]+1 , max ) ;
}
s2[i] = max ;
}
// 第1~i位同学在升序这能站第几位的最大 + 第 i+1 ~ n 位同学在降序这能站第几位的最大
int ans = 0 ;
for( int i = 0 ; i < N ; i++ ) {
for( int j = i+1 ; j < N ; j++ )
ans = Math.max( s1[i]+s2[j] , ans) ;
}
// 总人数 - 留下了排列的人数 = 出列的人数
ans = N - ans ;
System.out.println( ans );
}
private static int getInt() {
try {
sr.nextToken() ;
} catch (IOException e) {
e.printStackTrace();
}
return (int) sr.nval ;
}
}
四、总结:
总的来说就是如何排列最长升序子序列和最长降序子序列,合唱队列的左边部分选最长升序子序列中的左边部分,合唱队列的右边部分选最长降序子序列中的右边部分(选的是该同学在最长升序子序列/最长降序子序列中排第几位),由于同学们的位置是固定的,我们就容易找出合唱队列最多能有多少人了,最少需要几位同学出列的答案也出来了~
转载自:https://juejin.cn/post/7076681733063573512