用了O(n^2)的方法会超时…
所以学习了另一种O(nlogn)的方法:

纯说一些东西有点抽象,所以还是举个栗子:

定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素。

举例:原序列为1,5,8,3,6,7

栈为1,5,8,此时读到3,用3替换5,得到1,3,8; 再读6,用6替换8,得到1,3,6;再读7,得到最终栈为1,3,6,7。最长递增子序列为长度4。

找位置的时候就可以用到二分啦…

这里还用到了lower_bound函数(从已经排好序的的序列a中利用二分搜索找出指向满足ai>=k的最小的指针。类似的函数还有upper_bound,这一函数求出的是指向ai>k的ai的最小的指针。长度为n的有序数组a中k的个数,可以用upper_bound(a,a+n,k)-lower_bound(a,a+n,k)求出)

#define INF 0x3f3f3f3f
int a[50100];
int dp[50100];
int main()
{
    int n,i,loc,len;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    scanf("%d",&a[i]);
    fill(dp,dp+n,INF);
    len=0;
    for(i=0;i<n;i++)
    {
        loc=lower_bound(dp,dp+len,a[i])-dp;
        dp[loc]=a[i];
        if(loc==len)len++;
    }
    printf("%d\n",len);
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

51nod 1183 编辑距离 Previous
状态压缩dp Next