[Luogu 1020 导弹拦截 ]

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 //2018.07.13
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 const int MAXN=1e5+1;
 8 int a[MAXN],g[MAXN],ml=0,n=0;
 9 int* lowerBound(int* begin,int* end,int val){
10     //在不升序列中查找 
11     int* mid,*l=begin,*r=end;
12     while(l<r){
13         mid=(r-l)/2+l;
14         if(*mid<val)r=mid;//8 7 6 4 4 4 3 1
15         else l=mid+1;
16     }
17     return l;
18 }
19 int* lower_Bound(int* begin,int* end,int val){
20     //在不降序列中查找 
21     int *mid,*l=begin,*r=end;
22     while(l<r){
23         mid=(r-l)/2+l;
24         if(*mid>=val)r=mid;//1 2 3 4 6 7 8 9
25         else l=mid+1;
26     }
27     return l;
28 }
29 int main()
30 {
31     while(scanf("%d",&a[0])==1)a[++n]=a[0];
32     g[ml=1]=a[1];
33     for(int i=2;i<=n;i++){
34         if(a[i]<=g[ml])g[++ml]=a[i];
35         else
36         {
37             int pos=lowerBound(g+1,g+ml+1,a[i])-g;
38             g[pos]=a[i];
39         }
40     }
41     printf("%d\n",ml);
42     g[ml=1]=a[1];
43     for(int i=2;i<=n;i++){
44         if(a[i]>g[ml])g[++ml]=a[i];
45         else{
46             int pos=lower_Bound(g+1,g+ml+1,a[i])-g;
47             g[pos]=a[i];
48         }
49     }
50     printf("%d",ml);
51     return 0;
52 }
导弹拦截

 

//蒟蒻出品,如有错误,欢迎指正.

posted @ 2017-11-07 20:22  昤昽  阅读(153)  评论(0)    收藏  举报