hdu 1950 Bridging signals

链接

[http://acm.hdu.edu.cn/showproblem.php?pid=1950]

题意

LIS

分析

因为一般那个dp是n^2的所以会超时
必须用那个nlogn的。
大佬链接
[https://blog.csdn.net/shuangde800/article/details/7474903]
这个地方就是用一个数组记录
d[len]表示到当前长度为len的可能有很多个,你就记录末尾那个数最小的。
最长上升子序列(LIS)的典型变形,熟悉的n^2的动归会超时。LIS问题可以优化为nlogn的算法。
定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素。
注意d中元素是单调递增的,下面要用到这个性质。
首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i];
否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 d[j] = a[i];
最终答案就是len
利用d的单调性,在查找j的时候可以二分查找,从而时间复杂度为nlogn。

代码

/*
	HDU 1950 Bridging signals
			-----最长上升子序列nlogn算法
*/
 
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 40005
int arr[MAXN],ans[MAXN],len;

int main()
{
  //freopen("in.txt","r",stdin);
	int T,p,i,j,k;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&p);
		for(i=1; i<=p; ++i)
			scanf("%d",&arr[i]);
		
		ans[1] = arr[1];
		len=1;
		for(i=2; i<=p; ++i)
			if(arr[i]>ans[len])
				ans[++len]=arr[i];
			else{
				int pos=lower_bound(ans,ans+len,arr[i])-ans;   
				ans[pos] = arr[i];
		}
		printf("%d\n",len);
	}
	return 0;
}
posted @ 2019-03-29 16:46  ChunhaoMo  阅读(84)  评论(0)    收藏  举报