LIS问题

LIS问题是经典的DP问题,设F[i]为以i结尾的LIS长度,转移方程为:

F[i]=max(0,F[j] | i>j,A[i]>A[j])+1

不难看出这样的复杂度是O(n^2)的,有的时候实在难以承受。

实际上LIS问题存在O(nlogn)的算法

首先我们肯定这样一个事实:

对于F[i]=F[j],且A[i]小于A[j],则我们可以发现 i 绝对比 j 好。

所以我们设g[k]为F=k的最小A(不存在设为INF),不难发现g是单调递增的(否则不符合g的定义)

所以我们在计算F数组时,可以在g中二分查找最后一个j,使A[i]>A[j],则将i作为j的后续状态一定是最优的。

然后我们再用 i 更新 j+1,所以算法压缩到了O(nlogn)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define read(x) scanf("%d",&x)

using namespace std;

const int maxn=100000+10;
const int INF=(1<<31)-1;

int n,a[maxn],d[maxn],g[maxn];

int main()
{
  read(n);
  rep(i,1,n)
	 read(a[i]);
  rep(i,0,n) g[i]=INF;
  
  rep(i,1,n)
  {
	int k=lower_bound(g+1,g+n+1,a[i])-g; //在所有g中二分查找
	d[i]=k;
	g[k]=a[i]; //更新g数组
  }
  
  int ans=0;
  
  rep(i,1,n)
    ans=max(d[i],ans);
  printf("%d\n",ans);
  return 0;
}
posted @ 2016-04-06 22:33  Krew  阅读(214)  评论(0)    收藏  举报