合唱队形
描述
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<…Ti+1>…>TK(1<=i<=K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
格式
输入格式
输入的第一行是一个整数N(2<=N<=100),表示同学的总数。第一行有n个整数,用空格分隔,第i个整数Ti(130<=Ti<=230)是第i位同学的身高(厘米)。
输出格式
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
样例1
样例输入1
8
186 186 150 200 160 130 197 220
样例输出1
4
限制
每个测试点1s
解题
分别得出最长增序列(严格增)和最长降序列(严格降)(就是分别对两端就最长增序列),然后记录每一个位置的点作为结束增或起始降的长度,min(Upper[i] + Lower[i])就是题目求出的最长合唱团序列 + 1(中间位置计算了两次),用总人数减去最长合唱团序列长度就是题目所求的解。
代码
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
const int maxn = 102;
int T[maxn], dp[maxn];
int Upper[maxn], Lower[maxn];
int up_bound(int l, int r, int x) {
while (l < r) {
int mid = (l + r) >> 1;
if (x <= dp[mid]) {
//目标!!!!!!(以后记住!!!)
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
int main() {
int N;
cin >> N;
for (int i = 1; i <= N; i++) cin >> T[i];
int len1 = 1;
dp[1] = T[1];
Upper[1] = 1;
for (int i = 2; i <= N; i++) {
if (T[i] > dp[len1]) {
dp[++len1] = T[i];
Upper[i] = len1;
} else {
int up = up_bound(1, len1, T[i]);
dp[up] = T[i];
Upper[i] = up;
}
}
int len2 = 1;
dp[1] = T[N]; //这里注意从后面开始遍历的索引的对应关系
Lower[N] = 1;
for (int i = N - 1; i >= 1; i--) {
if (T[i] > dp[len2]) {
dp[++len2] = T[i];
Lower[i] = len2;
} else {
int up = up_bound(1, len2, T[i]);
// cout << up << "," << T[i] << endl;
dp[up] = T[i];
Lower[i] = up;
}
}
int ans = 0;
for (int i = 1; i <= N; i++) {
ans = max(ans, Upper[i] + Lower[i]);
}
cout << N - ans + 1 << endl;
system("pause");
return 0;
}