注意事项:
 本题为"线性dp—最长上升子序列的长度" 和 “最长上升子序列模型—怪盗基德的滑翔翼” 和 “最长上升子序列模型—登山” 的扩展题,所以dp思路这里就不再赘述。
题目:
 N位同学站成一排,音乐老师要请其中的 
    
     
      
       
        (
       
       
        N
       
       
        −
       
       
        K
       
       
        )
       
      
      
       (N-K)
      
     
    (N−K) 位同学出列,使得剩下的 
    
     
      
       
        K
       
      
      
       K
      
     
    K 位同学排成合唱队形。
 
 你的任务是,已知所有 N 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
 输入的第一行是一个整数 
    
     
      
       
        N
       
      
      
       N
      
     
    N,表示同学的总数。
 第二行有 
    
     
      
       
        N
       
      
      
       N
      
     
    N 个整数,用空格分隔,第 
    
     
      
       
        i
       
      
      
       i
      
     
    i 个整数 
    
     
      
       
        
         T
        
        
         i
        
       
      
      
       T_i
      
     
    Ti 是第 
    
     
      
       
        i
       
      
      
       i
      
     
    i 位同学的身高(厘米)。
输出格式
 输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
数据范围
 
    
     
      
       
        2
       
       
        ≤
       
       
        N
       
       
        ≤
       
       
        100
       
      
      
       2 \le N \le 100
      
     
    2≤N≤100,
 
    
     
      
       
        130
       
       
        ≤
       
       
        
         T
        
        
         i
        
       
       
        ≤
       
       
        230
       
      
      
       130 \le T_i \le 230
      
     
    130≤Ti≤230
输入:
8
186 186 150 200 160 130 197 220
 
输出:
4
 
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int w[N], f1[N], f2[N];
int n;
//最长上升子序列模板,(int* f)是引用arr
void lis(int* f)
{
    for (int i = 1; i<=n; i++) {
        f[i] = 1;
        for (int j = 1; j<i; j++) {
            if (w[j] < w[i]) f[i] = max(f[i], f[j]+1);
        }
    }
}
int main ()
{
    //接收数据
    cin >> n;
    for (int i = 1; i<=n; i++) cin >> w[i];
    //求两遍,一次最长上升子序列,一次最长下降子序列
    lis(f1);
    reverse(w+1, w+n+1);
    lis(f2);
    
    //把每个峰值点的上升和下降加在一起,算所有点作为峰值的max即可
    int res = 0;
    for (int i = 1; i<=n; i++) x = max(x, f1[i]+f2[n-i+1]); //这里因为下降子序列是反着求的,所以下标也是需要反着来
    cout << n-res+1 << endl;	//这里是和“登山”那题的唯一不同点,我们是要取最少需要多少人出列。
    return 0;
}
 
思路:
 很简单,前面的 计算/思路 和登山那题完全一样,最后输出的时候只要用 总人数 - 峰值Max + 1 即可计算出需要多少人出列。
究极水题!
声明:
 算法思路来源为y总,详细请见https://www.acwing.com/
 本文仅用作学习记录和交流



















