P1091 [NOIP2004 提高组] 合唱队形
题面
\(n\) 位同学站成一排,音乐老师要请其中的 \(n-k\) 位同学出列,使得剩下的 \(k\) 位同学排成合唱队形。
合唱队形是指这样的一种队形:设 \(k\) 位同学从左到右依次编号为 \(1,2,\) … \(,k\),他们的身高分别为 \(t_1,t_2,\) … \(,t_k\),则他们的身高满足 \(t_1< \cdots <t_i>t_{i+1}>\) … \(>t_k(1\le i\le k)\)。
你的任务是,已知所有 \(n\) 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
思路
其实思路很简单,就是跑两遍最长上升子序列,然后再枚举中间的求最大值。
最长上升子序列问题
本题 \(O(n^2)\) 算法可过。
方程如下:
\[f[i]=\max_{j<i \text{ and } a_j < a_i} \{ f[j] \} + 1
\]
代码
#include <bits/stdc++.h>
using namespace std;
int n, a[105], f[3][105], ans = INT_MIN;
int main() {
cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
if (a[i] > a[j]) {
f[0][i] = max(f[0][i], f[0][j] + 1);
}
}
}
for (int i = n; i >= 1; i--) {
for (int j = n + 1; j > i; j--) {
if (a[i] > a[j]) {
f[1][i] = max(f[1][i], f[1][j] + 1);
}
}
}
for (int i = 1; i <= n; i++) {
ans = max(f[0][i] + f[1][i]-1, ans);
}
ans=n-ans;
cout << ans << endl;
return 0;
}