码迷,mamicode.com
首页 > 其他好文 > 详细

The Longest Increasing Subsequence (LIS)

时间:2015-08-01 20:28:08      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:

传送门

十分重要的基础DP问题,是学习用各种方式优化DP的一个很好的例子。

设DP[i]表示以a[i]结尾的LIS的长度,则状态转移方程为

DP[1]=1

DP[i] = max{DP[j], j<i && a[j]<a[i]} + 1, i>1

暴力求解复杂度为O(N^2)。

优化1

考虑函数f(L):长度为 L 的 Increasing Sequence (IS) 的最小结尾, 显然f(L)是单调递增的。

从左到右扫描数组,维护动态的f(L)。

再看上面的DP方程,考虑我们维护的这个函数f(L)如何加速DP状态转移时所需的查询。

显然我们以a[i]为key,二分查询f(L),得到max{L, f(L)<a[i]}

复杂度降为O(N*logN)

这一类DP优化方法可归纳为 加速DP Query

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=1e6+10, oo=1e6;
int A[MAX_N], f[MAX_N];
//二分法: binary_search(y, f())
//设有一个单调(不要求严格单调)的函数f()
//可以在O(log N)的时间内求解以下问题:
//给定y,求满足f(x)<=y/f(x)>=y的最大/最小的x
//

int binary_search(int y, int l, int r){ //y is the key
  int mid;
  while(r-l>1){ //r is illegal
    mid=(l+r)>>1;
    if(f[mid]<y){
      l=mid;
    }
    else r=mid;
  }
  return l;
}

int main(){
  //freopen("in", "r", stdin);
  int N, ans=0;
  scanf("%d", &N);
  for(int i=1; i<=N; i++) scanf("%d", A+i);
  
  f[0]=0;
  for(int i=1; i<=N; i++) f[i]=oo;
  for(int i=1; i<=N; i++){
    int tmp=binary_search(A[i], 0, ans+1)+1;
    ans=max(ans, tmp);
    f[tmp]=min(f[tmp], A[i]);
  }
  printf("%d\n", ans);
  return 0;
}

 优化2

 

The Longest Increasing Subsequence (LIS)

标签:

原文地址:http://www.cnblogs.com/Patt/p/4693665.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!