合唱队形
题目描述
核心思路
假设最优解的中心是第 i i i个人,则 T 1 , T 2 , ⋯ , T i T_1,T_2,\cdots ,T_i T1,T2,⋯,Ti一定是以 T i T_i Ti结尾的最长上升子序列,同理, T k , T k − 1 , ⋯ , T i T_k,T_{k-1},\cdots ,T_i Tk,Tk−1,⋯,Ti也一定是以 T i T_i Ti结尾的最长上升子序列,因此,我们可以先预处理出:
- 从前往后以每个点结尾的最长上升子序列长度 f[i];
- 从后往前以每个点结尾的最长上升子序列长度 g[i];
- 那么以 k k k为中心的最大长度就是 r e s = f [ i ] + g [ i ] − 1 res=f[i]+g[i]-1 res=f[i]+g[i]−1,遍历 k = 1 , 2 , ⋯ , n k=1,2,\cdots ,n k=1,2,⋯,n取最大值即可。
- 因为题目是求最少去掉几个人,由于我们已经求出了合唱队中最多有 r e s res res个人,那么最少去掉 n − r e s n-res n−res个人即可。
代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int n;
int a[N];
int f[N];
int g[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
//预处理出从前往后以每个点结尾的最长上升子序列长度 f[i];
for(int i=1;i<=n;i++)
{
f[i]=1;
for(int j=1;j<i;j++)
{
if(a[j]<a[i])
f[i]=max(f[i],f[j]+1);
}
}
//预处理出从后往前以每个点结尾的最长上升子序列长度 g[i];
for(int i=n;i>=1;i--)
{
g[i]=1;
for(int j=n;j>i;j--)
{
if(a[j]<a[i])
g[i]=max(g[i],g[j]+1);
}
}
int res=0;//合唱队最多的人数
for(int i=1;i<=n;i++)
res=max(res,f[i]+g[i]-1);
int ans=n-res;//最少去掉的人数
printf("%d\n",ans);
return 0;
}