HDU 1950 Bridging signals (LIS,O(nlogn))
题意:
给一个数字序列,要求找到LIS,输出其长度。
思路:
扫一遍+二分,复杂度O(nlogn),空间复杂度O(n)。
具体方法:增加一个数组,用d[i]表示长度为 i 的递增子序列的最后一个元素,且该元素总是保持当前最小。初始化d[1]=A[i],当前LIS的长度len=1。从 2 to n,若A[i]>d[len],则d[++len]=A[i],否则,在数组d中找到A[i]应该插入的位置,代替掉那个第一个比它大的数字,比如d[k]<A[i]<=d[k+1],直接将A[i]代替掉d[k+1]。完成后len就是LIS的长度了。
1 #include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <map> 7 #include <algorithm> 8 #include <vector> 9 #include <iostream> 10 #define pii pair<int,int> 11 #define INF 2147483647 12 #define LL unsigned long long 13 using namespace std; 14 const double PI = acos(-1.0); 15 const int N=40100; 16 const int mod=1e9+7; 17 int a[N], d[N]; 18 int* lower_( int *s,int *e,int val ) //二分找值,返回下标 19 { 20 int L=0, R=e-s-1, mid; 21 while(L<R) 22 { 23 mid=R-(R-L+1)/2; //保证至少减少1 24 if( s[mid]<val ) L=mid+1;//至少增加1 25 else R=mid; 26 } 27 return &s[R]; 28 } 29 30 int main() 31 { 32 freopen("input.txt", "r", stdin); 33 int t, n, len; 34 cin>>t; 35 while(t--) 36 { 37 scanf("%d",&n); 38 for(int i=1; i<=n; i++) scanf("%d",&a[i]); 39 len=1; 40 d[len]=a[1]; 41 42 for( int i=2; i<=n; i++ ) 43 { 44 if( a[i]>d[len] ) d[++len]=a[i]; 45 else *lower_(d+1,d+len+1,a[i])=a[i]; 46 //else *lower_bound(d+1,d+len+1,a[i])=a[i]; 上一行代码可换成此行 47 } 48 printf("%d\n",len); 49 } 50 return 0; 51 }