题目:奥运大包围
题目描述
题目描述:
为了迎接奥运,市体育局举行手拉手大包围活动,开始时N个人手拉手围成一个圈。后来这些人中的一些按顺序向里面出圈形成一个新圈。从而使原圈形成一个从高到低,最低与最高连接的圈。新圈重复相同的操作,直到没有人要出圈为止。问最少要形成多少个这样的圈。
输入格式
输入:第一行N个人,第二行输入N个人的身高(每个身高中用空格隔开)N<=1000
输出格式
输出:最少形成多少个这样的圈。
定理:下降子序列的个数等于最长不下降子序列的长度。
稍微想一想就明白了。
将圈拆成段枚举就是了。二分优化:最长不下降子序列的O(n*logn)算法
话说和[NOIP1999]拦截导弹 差不多,应该也可以用贪心。
1 #include<iostream> 2 //#include<fstream> 3 using namespace std; 4 //ifstream fin("cin.in"); 5 6 int n,h[2005],c[2005],len=0,ans=10000; 7 8 int Find(int x){ 9 int l=1,r=len,mid=(len+1)>>1; 10 while(l<=r) 11 { 12 mid=(l+r)>>1; 13 if(c[mid]<=x) l=mid+1; 14 else if(c[mid]>x) r=mid-1; 15 } 16 return l; 17 } 18 19 int main() 20 { 21 cin>>n; 22 for(int i=1;i<=n;++i) cin>>h[i],h[i+n]=h[i]; 23 24 for(int i=1;i<=n;++i) 25 { 26 len=1; 27 c[1]=h[i]; 28 29 for(int j=i+1;j-i<n;++j) 30 { 31 int k=Find(h[j]); 32 if(k==len+1) len++; 33 c[k]=h[j]; 34 } 35 ans=min(ans,len); 36 } 37 38 cout<<ans<<endl; 39 // system("pause"); 40 return 0; 41 42 }