最长上升子序列_nlogn

f[i]代表当前长度为i的上升子序列的最小结尾

以len记录当前最长上升子序列长度

DP分类讨论(1.维护最大长度 2.维护最小结尾)

1.当前元素a[i]>f[len],更新len及f[len+1]

2.否则,在f中寻找下界为a[i](>=此元素)的位置pos,此时f[0~pos-1]都<a[i],a[i]将处于长度为(pos-1)+1的上升子序列的结尾,于是更新f[pos]为a[i],维护最小结尾.

lower_bound(a+l,a+r+1,x)-a 指在a[l,r]中找到下界为x的位置

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#define ll long long
using namespace std;
const int MAXN=1e6+10;
int n,len;
int f[MAXN],a[MAXN];
inline int in()
{
	int x=0,flag=1;
	char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') flag=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*flag;
}
int main()
{
	n=in();
	for (int i=1;i<=n;i++) a[i]=in();
	len=1;
	f[1]=a[1];
	for (int i=2;i<=n;i++)
	{
		if (a[i]>f[len]) f[++len]=a[i];
		else 
		{
			/*
			int l=1,r=len,mid=0,pos=0;
			while (l<=r)
			{
				mid=(l+r)/2;
				if (f[mid]<a[i]) l=mid+1;
				else pos=mid,r=mid-1;
			}
			*/
			int pos=lower_bound(f+1,f+len+1,a[i])-f;
			f[pos]=a[i];
		}
	}
	printf("%d",len);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wangyc123456/article/details/80253843