LIS 堆优化

LIS 问题描述

给出一个数列,找出其中最长的单调递减(或递增)子序列。
例如,A{10,22,9,33,21,50,41,60,80} LIS 的长度是 6,LIS 为 {10,22,33,50,60,80}。

分析

定义 f[i] 表示以 A[i] 结尾的 LIS 的长度,动态转移方程如下:
f[i]=max(f[i],f[j]+1) (j<i and A[j]<A[i])

更人性化的解读参考 GavinZheng- 最长上升子序列

时间复杂度 O(n^2)

方案优化

用 l[i] 表示已遍历的长度为 i 的 LIS最小的结尾数字
则可证明,l[] 数组的元素保持单调上升,于是用二分优化,

#include<iostream>
#include<cstdio>
using namespace std;
int n,a,l[10001],cnt;
int low_bound(int * arr,int l,int r,int v){while(l<r){int mid=(l+r+1)>>1;
		if(arr[mid]>=v)r=mid-1;
		else l=mid;
	}
	return l;
}
int main(){cin>>n;
	for(int i=1;i<=n;i++){cin>>a;
		int j=low_bound(l,0,cnt,a);
		if(++j>cnt)l[++cnt]=a;
		if(l[j]>a)l[j]=a;
	}
	cout<<cnt;
	return 0;
}

时间复杂度 O(nlogn)

原文地址:https://www.cnblogs.com/sshwy/p/11144066.html