【DP】最长不下降子序列问题(二分)
Description
给你一个长度为n的整数序列,按从左往右的顺序选择尽量多的数字并且满足这些数字不下降。
Thinking
朴素dp算法:F[i]表示到第i位为止的最长不下降子序列长度 F[i]=max(F[j])+1,其中(j<i且a[j]<=a[i]) 时间复杂度:O(n2) 考虑维护一个队列g,用g[i]表示长度为i的最长不下降子序列结尾的最小值。根据g[i]的单调性,可以用二分查找的方法快速找到以当前数a[i]结尾的最长不下降子序列.
Code
1 #include<cstdio> 2 #include<cstring> 3 #define FA(i,s,t) for(int i=s;i<=t;i++) 4 #define FD(i,s,t) for(int i=s;i>=t;i--) 5 using namespace std; 6 7 int n; 8 int num[10000]; 9 int g[10000],f[10000]; 10 void Insert(int x,int s,int t) //不使用递归的方法提高效率 11 { 12 int left,right,mid; 13 left=s; 14 right=t; 15 while(left<=right) 16 { 17 mid=(left+right)/2; 18 if(g[mid]==x) 19 { 20 while(g[mid]==x) ++mid; 21 g[mid]=x; 22 return; 23 } 24 if(g[mid]>x) right=mid-1; 25 if(g[mid]<x) 26 { 27 if(g[mid+1]>x) 28 { 29 g[mid+1]=x; 30 return; 31 } 32 left=mid+1; 33 } 34 } 35 } 36 int main() 37 { 38 scanf("%d",&n); 39 FA(i,1,n) 40 { 41 scanf("%d",&num[i]); 42 } 43 memset(g,0,sizeof(g)); 44 int t=1; 45 FA(i,1,n) 46 { 47 if(num[i]>=g[t-1]) 48 { 49 g[t]=num[i]; 50 t++; 51 } 52 else 53 { 54 Insert(num[i],0,t); 55 } 56 } 57 int ans=t-1; 58 printf("%d\n",ans); 59 return 0; 60 }
----不要温顺地走进那良宵