luogu P1091&&NOIP2004 合唱队列
这道题是一道很好的DP入门题。考察了选手对于LIS的熟练程度。
所以在此之前,我先简单介绍一下LIS---最长上升子序列(或者最长不下降子序列);
给出数列 L ,L由若干个实数组成,分别表示a1,a2,a3......ak;现在我们要求求出它的单调性的递增的子集。这样简称LIS。
这样我们划分子问题,用F[i] 表示以 i 结尾的LIS,这样描述状态之间的转移:max{F[j]+1} || j<i&&f[j]+1>F[i];
这样我们就可以清楚的解决这个问题啦。
很明显,题目中说的要维护这种单调性:左<中<右;但是LIS维护的是一种持续的单调性呀!
那我们就分开来看,首先是a1到Ti,然后就是Ti到ak,这大概就是题目中所描述的单调性,这样我们就可以分别求出这段LIS的长度,再减去总长就OK拉。
即一遍递推算出最长上升子序列,再一遍递推算出最长下降子序列,再维护一遍max,再总数n-max,这样就OK啦。
1 #include <iostream>
2 #include <algorithm>
3 const int MAX =1000+10;
4 using namespace std;
5 int a[MAX]={0},f1[MAX]={0},f2[MAX]={0},best=0;
6 int main(){
7 ios::sync_with_stdio(false);
8 cin.tie(0);
9 register int i,j;
10 int n;cin>>n;
11 for(i=0;i<n;++i)cin>>a[i];
12 for(i=0;i<n;++i){
13 f1[i]=1;
14 for(j=0;j<i;++j)
15 if(a[j]<a[i]&&f1[j]+1>f1[i])
16 f1[i]=f1[j]+1;
17 }
18
19 for(i=n-1;i>=0;--i){
20 f2[i]=1;
21 for(j=n-1;j>i;--j)
22 if(a[j]<a[i]&&f2[j]+1>f2[i])
23 f2[i]=f2[j]+1;
24 }
25 for(i=0;i<n;++i){
26 best=max(best,f1[i]+f2[i]-1);
27 }
28 cout<<n-best<<'\n';
29 return 0;
30 }

浙公网安备 33010602011771号