链接
[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;
}