题解:洛谷 P1091 [NOIP 2004 提高组] 合唱队形

【题目来源】

洛谷:P1091 [NOIP 2004 提高组] 合唱队形 - 洛谷

【题目描述】

\(n\) 位同学站成一排,音乐老师要请其中的 \(n−k\) 位同学出列,使得剩下的 \(k\) 位同学排成合唱队形。

合唱队形是指这样的一种队形:设 \(k\) 位同学从左到右依次编号为 \(1,2, … ,k\),他们的身高分别为 \(t_1,t_2, … ,t_k\),则他们的身高满足 \(t_1<⋯<t_i>t_{i+1}> … >t_k(1≤i≤k)\)

你的任务是,已知所有 \(n\) 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

【输入】

共二行。

第一行是一个整数 \(n(2≤n≤100)\),表示同学的总数。

第二行有 \(n\) 个整数,用空格分隔,第 \(i\) 个整数 \(t_i(130≤t_i≤230)\) 是第 \(i\) 位同学的身高(厘米)。

【输出】

一个整数,最少需要几位同学出列。

【输入样例】

8
186 186 150 200 160 130 197 220

【输出样例】

4

【算法标签】

《洛谷 P1091 合唱队形》 #动态规划DP# #单调队列# #线性DP# #NOIP提高组# #2004#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 105;  // 定义最大序列长度
int n;               // 序列实际长度
int a[N];            // 存储原始序列
int f[N];            // f[i]表示以a[i]结尾的最长上升子序列长度
int g[N];            // g[i]表示以a[i]开头的最长下降子序列长度
int ans;             // 存储最终结果

int main()
{
    // 输入序列长度和元素
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
  
    // 计算每个位置的最长上升子序列长度(从左向右)
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j < i; j++)
        {
            if (a[i] > a[j])
                f[i] = max(f[i], f[j] + 1);
        }
    }
  
    // 计算每个位置的最长下降子序列长度(从右向左)
    for (int i = n - 1; i >= 1; i--)
    {
        for (int j = n; j > i; j--)
        {
            if (a[i] > a[j])
                g[i] = max(g[i], g[j] + 1);
        }
    }
  
    // 找出f[i]+g[i]的最大值
    for (int i = 1; i <= n; i++)
        ans = max(ans, f[i] + g[i]);
  
    // 计算需要移除的元素数量(总长度减去最长山峰序列长度)
    ans++;
    cout << n - ans << endl;
  
    return 0;
}

【运行结果】

8
186 186 150 200 160 130 197 220
4
posted @ 2026-02-20 19:25  团爸讲算法  阅读(7)  评论(0)    收藏  举报