P1091 合唱队形 DP 最长升序列维护

题目描述

NN位同学站成一排,音乐老师要请其中的(N-KNK)位同学出列,使得剩下的KK位同学排成合唱队形。

合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K1,2,,K,他们的身高分别为T_1,T_2,…,T_KT1,T2,,TK, 则他们的身高满足T_1<...<T_i>T_{i+1}>…>T_K(1 le i le K)T1<...<Ti>Ti+1>>TK(1iK)。

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

输入输出格式

输入格式:

共二行。

第一行是一个整数N(2 le N le 100)N(2N100),表示同学的总数。

第二行有nn个整数,用空格分隔,第ii个整数T_i(130 le T_i le 230)Ti(130Ti230)是第ii位同学的身高(厘米)。

输出格式:

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

输入输出样例

输入样例#1: 复制
8
186 186 150 200 160 130 197 220
输出样例#1: 复制
4


每次都是看到题解恍然大悟 真是弱鸡

要求最少出队 那么就是求最长的合唱队形
只要从左边和右边各遍历一遍 求出dp 最长上升序列和下降序列 再枚举中间点即可

#include<bits/stdc++.h>
using namespace std;
//input
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m);
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define N 100005
#define inf -0x3f3f3f3f
int dp[N];
int dp2[N];
int a[N];
int main()
{
    int n;
    RI(n);
    rep(i,1,n)
     RI(a[i]);
    rep(i,1,n)
    {
        dp[i]=1;
        for(int j=1;j<i;j++)
        if(a[j]<a[i])dp[i]=max(dp[i],dp[j]+1);
    }
    for(int i=n;i>=1;i--)
    {
        dp2[i]=1;
        for(int j=n;j>i;j--)
        if(a[j]<a[i])dp2[i]=max(dp2[i],dp2[j]+1);
    }
    int maxx=0;
    rep(i,1,n)
     maxx=max(maxx,dp[i]+dp2[i]-1 );
     cout<<n-maxx<<endl;
    return 0;
}











原文地址:https://www.cnblogs.com/bxd123/p/10508168.html