NC16664 合唱队形
合唱队形
https://ac.nowcoder.com/acm/problem/16664
分析
首先,要让最少的同学出列,就等价于让尽量多的同学留在队伍中。
观察到合唱队形满足 ,在合唱队形中,以第 个同学为分界点(分界点即为最高点),从 到 递增,从 到 递减。
设原队形中第 个同学的身高为 。假设我们选取第 个同学作为合唱队形的最高点,那么要使尽量多的同学留在队伍中,合唱队形左边应该是 数组中从左到右以 结尾的 ;右边应该是 数组中从右到左以 结尾的的 。
我们可以预处理出 数组中正向和逆向的最长上升子序列长度,然后枚举合唱队形的最高点,就可以得到最多能有多少同学留在队伍中,也就能知道最少需要几位同学出列。
设 为从左到右以 结尾的 长度, 为从右到左以 为结尾的 长度。
有状态转移方程
当以 为最高点时,能留在队伍中的同学个数为 。
因此,答案为 。
代码
#include<iostream> #include<algorithm> #include<cstdio> #define N 103 using namespace std; int l[N],r[N]; int height[N]; int n,ans=0x3f3f3f3f; int main() { int i; cin>>n; for(i=1;i<=n;i++) scanf("%d",height+i); for(i=1;i<=n;i++) l[i]=r[i]=1;//LIS初始长度都为1 int j; //计算两个方向的LIS长度 for(i=2;i<=n;i++) { for(j=1;j<i;j++) { if(height[i]>height[j]) { l[i]=max(l[i],l[j]+1); } } } for(i=n-1;i>=1;i--) { for(j=n;j>i;j--) { if(height[i]>height[j]) { r[i]=max(r[i],r[j]+1); } } } //迭代更新最小值 for(i=1;i<=n;i++) ans=min(ans,n-(l[i]+r[i]-1)); cout<<ans<<endl; return 0; }