P1091 合唱队形[单调队列DP]

题目来源:洛谷

题目描述

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

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

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

输入输出格式

输入格式:

共二行。

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

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

输出格式:

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

输入输出样例

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

说明

对于50%的数据,保证有n20;

对于全部的数据,保证有n100。

解析:

这道题就非常经典了。

假设mid为最后留下来的中间那个最高的人。

首先我们容易想到分别从1~n,从n~1 LIS两次,这样就得到了两个关于留下来的人的单调队列,此时我们再查找一个能使得留下来的人最多的一个mid,即使得从1到mid的LIS和从n到mid的LIS总长度最长的mid,在这个情形下,我们就会得到最优解。

注意:1.我们使用的dp技术计算的是留下来的人数。

   2.由于在使用单调队列计算最大保留人数时,我们难免会多计算最中间那个mid一次,所以答案要减去1。

参考代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<string>
 7 #include<cstdlib>
 8 #include<queue>
 9 #include<vector>
10 #define INF 0x3f3f3f3f
11 #define PI acos(-1.0)
12 #define N 101
13 #define MOD 2520
14 #define E 1e-12
15 using namespace std;
16 int a[N],dp1[N],dp2[N];
17 int main()
18 {
19     int n,ans=-INF;
20     cin>>n;
21     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
22     fill(dp1+1,dp1+n+1,1);
23     fill(dp2+1,dp2+n+1,1);
24     for(int i=1;i<=n;i++)
25         for(int j=1;j<=i;j++)
26             if(a[j]<a[i]) dp1[i]=max(dp1[i],dp1[j]+1);
27         
28     for(int i=n;i>=1;i--)
29         for(int j=n;j>=i;j--)
30             if(a[j]<a[i]) dp2[i]=max(dp2[i],dp2[j]+1);
31     for(int i=1;i<=n;i++) ans=max(dp1[i]+dp2[i]-1,ans);
32     cout<<n-ans<<endl;
33     return 0;
34 }

猜你喜欢

转载自www.cnblogs.com/DarkValkyrie/p/11060560.html