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 }

 

posted @ 2018-09-17 18:33  _Gingoo  阅读(258)  评论(0)    收藏  举报