洛谷 P1091 合唱队形

来源:互联网 发布:js设置data属性值 编辑:程序博客网 时间:2024/05/17 03:42

题目描述

N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<…Ti+1>…>TK(1<=i<=K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入输出格式

输入格式:

输入文件chorus.in的第一行是一个整数N(2<=N<=100),表示同学的总数。第一行有n个整数,用空格分隔,第i个整数Ti(130<=Ti<=230)是第i位同学的身高(厘米)。

输出格式:

输出文件chorus.out包括一行,这一行只包含一个整数,就是最少需要几位同学出列。

输入输出样例

输入样例#1:

8
186 186 150 200 160 130 197 220

输出样例#1:

4
说明
对于50%的数据,保证有n<=20;
对于全部的数据,保证有n<=100。

分析

正反做一遍最长不下降,正确性显然

nlogn 求最长不下降子序列

我们设d[i]表示长度为i的最长不下降子序列最尾元素的最小值,显然d[i]<=d[i+1],d数组符合单调性。因此对于a[i]只需在d数组中二分即可

lower_bound && upper_bound

lower_bound(a+l,a+r+1,key)表示在a数组的l~r范围进行二份查找(注意你需要保证这个数组的单调性,可以加cmp来表达他的单调性,默认单调性是非递减),找到第一个>=key的位置并返回。
而upper_bound则是找到第一个>key的位置返回。
求最长不下降子序列可以利用C++STL中algorithm库里的这两个东西来减少代码量。

fo(i,1,n){        k=upper_bound(d+1,d+n+1,a[i])-d;        ans=max(ans,k);        d[k]=min(d[k],a[i]);}

代码

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#define N 200int read(){    int x=0,k=1;    char ch;    ch=getchar();    while(ch<'0' || ch>'9')    {        if(ch=='-')            k=-1;        ch=getchar();    }    while(ch>='0' && ch<='9')    {        x=x*10+ch-'0';        ch=getchar();    }    return x*k;}int p[N],u[N],d[N];int fu[N],fd[N];int main(){    int n;    n=read();    for(int i=1;i<=n;i++)        p[i]=read();    fu[1]=p[1];    int len=1;    for(int i=2;i<=n;i++)    {        if(fu[len]<p[i])            fu[++len]=p[i];            else fu[std::lower_bound(fu+1,fu+len+1,p[i])-fu]=p[i];            u[i]=len;    }    fd[1]=p[n];    len=1;    for(int i=n-1;i>=1;i--)    {        if(fd[len]<p[i])            fd[++len]=p[i];            else fd[std::lower_bound(fd+1,fd+len+1,p[i])-fd]=p[i];        d[i]=len;       }    int ans=0x7ffffff;    for(int i=1;i<=n;i++)        ans=std::min(ans,n-u[i]-d[i+1]);    printf("%d\n",ans);}
0 0
原创粉丝点击