【ACWing】896. 最长上升子序列 II

题目地址:

https://www.acwing.com/problem/content/898/

给定一个长 N N N数列 a a a,求严格单调递增的子序列的最长长度。

数据范围:
1 ≤ N ≤ 100000 1\le N\le 100000 1N100000
− 1 0 9 ≤ x ≤ 1 0 9 -10^9\le x\le 10^9 109x109
x x x是数列中的数

思路是偏序集分解定理。一个偏序集的最长链的长度,就是它能分解为最少多少个反链的个数。在这里可以将每个数与它的下标做成一个pair,并定义 ( i , a [ i ] ) < ( j , a [ j ] ) (i,a[i])<(j,a[j]) (i,a[i])<(j,a[j])当且仅当 i < j ∧ a [ i ] < a [ j ] i<j\land a[i]<a[j] i<ja[i]<a[j]。那么反链就是指 i < j ∧ a [ i ] ≥ a [ j ] i<j\land a[i]\ge a[j] i<ja[i]a[j]的情况了。我们只需要看最少能分解出多少个反链即可。思路参考https://blog.csdn.net/qq_46105170/article/details/108616895。这里用一个数组 f f f来存每条反链的最后一个数字。代码如下:

#include <iostream>
using namespace std;

const int N = 100010;
int n;
int a[N], f[N];

// 在f[0 : r]中找到第一个大于等于t的数字的下标
int binary_search(int f[], int r, int t) {
    
    
    if (r < 0) return -1;
    
    int l = 0;
    while (l < r) {
    
    
        int m = l + (r - l >> 1);
        if (f[m] >= t) r = m;
        else l = m + 1;
    }

    return f[l] >= t ? l : -1;
}

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

    int idx = 0;
    for (int i = 0; i < n; i++) {
    
    
        int pos = binary_search(f, idx - 1, a[i]);
        if (pos == -1) f[idx++] = a[i];
        else f[pos] = a[i];
    }

    cout << idx << endl;

    return 0;
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/113885425