n*log2(n) 的做法:利用 lower_bound
规律:
1.最长上升子序列:
g[Length] 为长度为 Length 的上升子序列的结尾数值的最小值 , g[x] < g[x+1]
2.最长不下降子序列:
g[Length] 为长度为 Length 的不下降子序列的结尾数值的最小值 , g[x] <= g[x+1]
3.最长下降子序列:
g[Length] 为长度为 Length 的下降子序列的结尾数值的最大值 , g[x] > g[x+1]
4.最长不上升子序列:
g[Length] 为长度为 Length 的不上升子序列结尾数值的最大值 , g[x] >= g[x+1]
{ 即 g[ ] 的单调性与 目标序列一致 }
开始时 ,Length=1,g[1]=a[1],以(4)为例,考虑一个新进的元素 a[i]:
if a[i]<=g[Length] then g[++Length]=a[i];
else in g[ ] to find g[pos] ,g[pos+1]=a[i] | g[pos] >= a[i] >g[Length+1]
即用 a[i]替换掉不升序列 g[ ] 中第一个小于 a[i] 的元素.
实现:二分!(玄学二分毁我三观...)
看代码:
1 //Copyright(C)Sunshine. 2 //2017.11.07 3 #include <cstdio> 4 #include <cstring> 5 const int N=1e5+1; 6 int a[N],g[N],MaxLength=0,n=0; 7 int LowerBound_D(int l,int r,int v) 8 { 9 while(l<r) 10 { 11 int mid=(r-l)/2+l; 12 if(g[mid]<v)r=mid; 13 else l=mid+1; 14 } 15 return l; 16 } 17 int LowerBound_I(int l,int r,int v) 18 { 19 while(l<r) 20 { 21 int mid=(r-l)/2+l; 22 if(g[mid]>=v)r=mid; 23 else l=mid+1; 24 } 25 return l; 26 } 27 int main() 28 { 29 while(scanf("%d",&a[0])==1)a[++n]=a[0]; 30 g[MaxLength=1]=a[1]; 31 for(int i=2;i<=n;i++) 32 { 33 if(a[i]<=g[MaxLength])g[++MaxLength]=a[i]; 34 else 35 { 36 int pos=LowerBound_D(1,MaxLength,a[i]); 37 g[pos]=a[i]; 38 } 39 } 40 printf("%d\n",MaxLength); 41 g[MaxLength=1]=a[1]; 42 for(int i=2;i<=n;i++) 43 { 44 if(a[i]>g[MaxLength])g[++MaxLength]=a[i]; 45 else 46 { 47 int pos=LowerBound_I(1,MaxLength,a[i]); 48 g[pos]=a[i]; 49 } 50 } 51 printf("%d\n",MaxLength); 52 return 0; 53 }
想看代码请戳这里
//蒟蒻出品,如有错误,欢迎指正.
时间: 2024-10-12 21:30:57