删除最少的人组成这种合唱队形,该问题可以化简为:满足该队形性质的最长序列,只要找到了该最长序列,用总人数减去序列长度就得到了最少删除的人数。
那么如何找这个序列呢?其实我们可以把他看成两部分,左侧是一个最长子序列问题,右侧也是一个最长子序列问题,他们在Ti处汇总。因此我们从左向右求一个最长递增子序列,从右向左再求一个最长递增子序列,然后得到两个dp数组,dp1,dp2
,在遍历每一个汇点i:dp1[i]+dp2[i]-1
就是以i点为中心所能形成的合唱队形的最大长度。
int main() {
int n; ll a[MAX], dp1[MAX], dp2[MAX];//dp1:正向最长递增子序列 dp2:反向最长递增子序列
while (cin >> n) {
for (int i = 1; i <= n; i++)cin >> a[i];
fill(dp1, dp1 + MAX, 1);
fill(dp2, dp2 + MAX, 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j < i; j++)
if (a[j]<a[i] && dp1[j] + 1>dp1[i]) dp1[i] = dp1[j] + 1;
for (int i = n; i >= 0; i--)
for (int j = n; j > i; j--)
if (a[i] > a[j] && dp2[j] + 1 > dp2[i])dp2[i] = dp2[j] + 1;
ll res = 0;
for (int i = 1; i <= n; i++)
if (dp1[i] + dp2[i] - 1 > res)res = dp1[i] + dp2[i] - 1;
cout << n - res << endl;
}
}