题解 | #合唱队#
链接:https://www.nowcoder.com/questionTerminal/6d9d69e3898f45169a441632b325c7b4
来源:牛客网
<di>
</di>
来源:牛客网
<di>
设KKK位同学从左到右依次编号为 1,2…,K ,他们的身高分别为T1,T2,…,TKT_1,T_2,…,T_KT1,T2,…,TK ,若存在i(1≤i≤K)i(1\leq i\leq K)i(1≤i≤K) 使得T1<T2<......<Ti−1<TiT_1<T_2<......<T_{i-1}<T_iT1<T2<......<Ti−1<Ti 且 Ti>Ti+1>......>TKT_i>T_{i+1}>......>T_KTi>Ti+1>......>TK,则称这KKK名同学排成了合唱队形。
通俗来说,能找到一个同学,他的两边的同学身高都依次严格降低的队形就是合唱队形。
例子:
123 124 125 123 121 是一个合唱队形
123 123 124 122不是合唱队形,因为前两名同学身高相等,不符合要求
123 122 121 122不是合唱队形,因为找不到一个同学,他的两侧同学身高递减。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
注意:不允许改变队列元素的先后顺序 且 不要求最高同学左右人数必须相等
数据范围: 1≤n≤3000 1 \le n \le 3000 \1≤n≤3000
输入描述:
用例两行数据,第一行是同学的总数 N ,第二行是 N 位同学的身高,以空格隔开
输出描述:
最少需要几位同学出列
示例1
输入
8 186 186 150 200 160 130 197 200
输出
4
说明
由于不允许改变队列元素的先后顺序,所以最终剩下的队列应该为186 200 160 130或150 200 160 130
1)某一个位置i对应的左侧最长上升子序列是其左侧第一个比之小的值最长上升子序列+1,以此类推
2)先找到每一个位置i左侧的最长上升子序列长度numL[i]:每一个位置左侧最长子序列长度等于其左侧比它小的所有位置的最长子序列长度中的最大值+1
3)再找到每一个位置i右侧的最长下降子序列长度numR[i]:每一个位置右侧最长子序列长度等于其右侧比它小的所有位置的最长子序列长度中的最大值+1
4)然后求出所有位置的最长序列长度=左侧最长子序列长度+右侧最长子序列长度-1(因为该位置被算了两次,所以减1)
5)然后用数目减去最长序列长度就是答案
3)再找到每一个位置i右侧的最长下降子序列长度numR[i]:每一个位置右侧最长子序列长度等于其右侧比它小的所有位置的最长子序列长度中的最大值+1
4)然后求出所有位置的最长序列长度=左侧最长子序列长度+右侧最长子序列长度-1(因为该位置被算了两次,所以减1)
5)然后用数目减去最长序列长度就是答案
#include<iostream> #include<string> #include<vector> #include<algorithm> #include <math.h> using namespace std; int main(){ int n = 0; while (cin >> n) { vector<int> num(n, 0); for (int i = 0; i < n; i++) { cin >> num[i]; } int res = 0; vector<int> numL(n , 0); vector<int> numR(n , 0); for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { if (num[i] > num[j]) { numL[i] = max(numL[i], numL[j]); } } numL[i] += 1; } for (int i = n - 1; i >= 0; i--) { for (int j = n - 1; j >= i; j--) { if (num[i] > num[j]) { numR[i] = max(numR[i], numR[j]); } } numR[i] += 1; } for (int i = 0; i < n; i++) { res = max(res, (numL[i] + numR[i] - 1)); } cout << (n - res) << endl; } }