AcWing 896. 最长上升子序列 II

题目传送门

1、与原始版本区别

原始版本:\(1≤N≤1000\),本题要求:\(1≤N≤100000\)

\(N\)的数据范围大了\(100\)倍,原始版本的题的时间复杂度是\(O(N^2)\),\(1000^2=1000000\),是\(1e6\),是可以\(1\)秒过的,但如果是\(100000^2=10000000000\),是\(1e10\),超时,需要要优化~

2、题解

#include <bits/stdc++.h>

using namespace std;
const int N = 100010;
/*
例 n: 7
arr : 3 1 2 1 8 5 6

stk : 3

1 比 3 小
stk : 1

2 比 1 大
stk : 1 2

1 比 2 小
stk : 1 2

8 比 2 大
stk : 1 2 8

5 比 8 小
stk : 1 2 5

6 比 5 大
stk : 1 2 5 6

stk 的长度就是最长递增子序列的长度

*/
int n, a[N];
//单调栈
int stk[N], idx;

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    //第一个数字入栈
    stk[++idx] = a[1];

    //讨论后面的n-1个数字
    for (int i = 2; i <= n; i++) {
        //如果该元素大于栈顶元素,将该元素入栈(对后序数字可能有用)
        if (a[i] > stk[idx]) stk[++idx] = a[i];
            //替换掉第一个大于或者等于这个数字的那个数
        else *lower_bound(stk + 1, stk + 1 + idx, a[i]) = a[i];
    }
    printf("%d\n", idx);
    return 0;
}

3、解题思路

栈内记录:【长度为\(i+1\)的递增子串中,末尾元素最小的是\(stk[i]\)】。

理解了这个问题以后就知道为什么新进来的元素要不就在末尾增加,要不就替代第一个大于等于它元素的位置。

这里的【替换】就蕴含了一个贪心的思想,对于同样长度的子串,我当然希望它的末端越小越好,这样以后我也有更多机会拓展。

原文地址:https://www.cnblogs.com/littlehb/p/15429000.html