SP57 SUPPER - Supernumbers in a permutation

题目传送门

考虑 dp 求出 \(f_i\) 表示以 \(i\) 结尾的最长上升子序列长度,\(g_i\) 表示以 \(i\) 开头的最长上升子序列长度。

有转移:

\[f_i=\max\limits_{1\le j<i\,\land\,a_j<a_i}f_j+1 \]

\[g_i=\max\limits_{i<j\le n\,\land\,a_i<a_j}g_j+1 \]

考虑经过一个位置 \(i\) 在最长上升子序列上,一定是以它往后最长的一个最长上升子序列,接在它之前的 \(j\) 位置后,然后从 \(j\) 位置往前延申一段最长上升子序列。

形式化地,经过一个位置 \(i\) 的最长上升子序列长度为:

\[g_i+\max\limits_{1\le j<i\,\land\,a_j<a_i}f_j \]

求出这个东西,看是否等于原序列的最长上升子序列。

考虑用扫描线解决下标的限制,线段树维护值域的限制,单组数据时间复杂度为 \(\mathcal{O}(n\log n)\),空间复杂度为 \(\mathcal{O}(n)\)

#include <bits/stdc++.h>
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
using namespace std; const int N = 1e5 + 1; 
int n, a[N], f[N], g[N], ans; vector<int> tmp;
struct SegmentTree {
    int mx[N << 2];
    void build(int x, int l, int r) {
        mx[x] = 0; if (l == r) return; int mid = (l + r) >> 1;
        build(ls(x), l, mid); build(rs(x), mid + 1, r);
    }
    void modify(int x, int l, int r, int k, int v) {
        if (l == r) return void(mx[x] = v); int mid = (l + r) >> 1;
        if (k <= mid) modify(ls(x), l, mid, k, v);
        else modify(rs(x), mid + 1, r, k, v); mx[x] = max(mx[ls(x)], mx[rs(x)]);
    }
    int query(int x, int l, int r, int ql, int qr) {
        if (ql > qr) return 0; if (ql <= l && r <= qr) return mx[x]; 
        int mid = (l + r) >> 1, ret = 0;
        if (ql <= mid) ret = query(ls(x), l, mid, ql, qr);
        if (qr > mid) ret = max(ret, query(rs(x), mid + 1, r, ql, qr)); return ret;
    }
} SGT;
signed main() {
    cin.tie(0), cout.tie(0), ios::sync_with_stdio(0);
    while (cin >> n) {
        for (int i = 1; i <= n; ++i) cin >> a[i]; SGT.build(1, 1, n); ans = 0;
        for (int i = 1; i <= n; ++i) {
            f[i] = SGT.query(1, 1, n, 1, a[i] - 1) + 1;
            SGT.modify(1, 1, n, a[i], f[i]); ans = max(ans, f[i]);
        }
        SGT.build(1, 1, n); tmp.clear();
        for (int i = n; i >= 1; --i) {
            g[i] = SGT.query(1, 1, n, a[i] + 1, n) + 1;
            SGT.modify(1, 1, n, a[i], g[i]);
        }
        SGT.build(1, 1, n);
        for (int i = 1; i <= n; ++i) {
            if (SGT.query(1, 1, n, 1, a[i] - 1) + g[i] == ans) 
                tmp.emplace_back(a[i]);
            SGT.modify(1, 1, n, a[i], f[i]);
        }
        cout << tmp.size() << '\n'; stable_sort(tmp.begin(), tmp.end());
        for (int i : tmp) cout << i << ' '; cout << '\n';
    }
    return 0;
}
posted @ 2023-10-04 21:25  lzyqwq  阅读(9)  评论(0)    收藏  举报