AcWing 896. 最长上升子序列 O(nlogn)模板题

题目链接:点击这里

在这里插入图片描述

从序列单调性的角度进行优化,LIS的O(nlogn)说白了其实是贪心算法。

( 4 , 2 , 3 , 1 , 2 , 3 , 5 ) (4, 2, 3, 1, 2, 3, 5) 为例,求其最长上升子序列。

策略:应该尽可能地让上升子序列的元素整体变小,以便可以加入更多的元素。

开辟一个新的数组 a r r [ 10 ] arr[10]

  1. 第一个数是 4 4 ,先加进去,那么为 { 4 } \left\{ 4 \right\}

  2. 再来看下一个数 2 2 ,它比 4 4 小,如果它与 4 4 替换是不是可以让目前子序列变得更小,更方便以后元素的加入呢?是的,所以现在为 { 2 } \left\{ 2 \right\}

  3. 再来看他的下一个元素 3 3 ,它比 2 2 大,所以加在后面,即 { 2 , 3 } \left\{ 2, 3 \right\}

  4. 再看下一个元素是 1 1 ,它比 3 3 要小,所以为了保证子序列整体尽可能的小,以便可以加入更多的元素,从目前的序列中查找出第一个比它大的数替换掉,那么就变成了 { 1 , 3 } \left\{ 1, 3 \right\}

  5. 下一个数是 2 2 ,那么序列变为 { 1 , 2 } \left\{ 1, 2 \right\}

  6. 再下一个数为 3 3 ,那么序列为 { 1 , 2 , 3 } \left\{ 1, 2, 3 \right\}

  7. 再下一个数为 5 5 ,那么序列为 { 1 , 2 , 3 , 5 } \left\{1, 2, 3, 5\right\}

最终序列里有 4 4 个元素,所以最长子序列的个数为 4 4 ,但是这个序列是一个伪序列,里面的元素并不是真正的最长上升子序列,而仅仅和最长上升子序列的个数一样。

{ 2 , 1 , 5 , 3 , 6 , 4 , 8 , 9 , 7 } \left\{ 2, 1, 5, 3, 6, 4, 8, 9, 7\right\} 为例,最终序列为 { 1 , 3 , 4 , 7 , 9 } \left\{1,3,4,7,9\right\} 不是LIS,但LIS的长度确实为 5 5

lower_bound( begin, end, num );
功能:从数组的 begin 位置到 end-1 位置二分查找第一个大于或等于 num 的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

#include<algorithm>
#include<iostream>
#include<cstdio>

using namespace std;
const int N = 100010;
int a[N], dp[N];

int main()
{
	int n;
	cin>>n;
    for(int i = 1; i <= n; ++i) cin>>a[i];
    
	int len = 1;
    dp[1] = a[1];
	for(int i = 2; i <= n; ++i)
    {
        if(a[i] > dp[len])
			dp[++len] = a[i];
        else
            *lower_bound(dp + 1, dp + len + 1, a[i]) = a[i];
    }
    
    cout<<len<<endl;
    return 0;
}
发布了811 篇原创文章 · 获赞 127 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/104856350