AcWing 4550. 超级跳跳跳

题目简化后就是 LIS 将原本的价值改成了 \(a_i\),我们设 \(f_i\) 表示对于前 \(i\) 个数,必定选 \(i\),那么 \(f_i=\max\limits_{a_i>a_k}\{f_k+a_i\}\)

// #define FILE_INPUT
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define rep(i, a, b) for (int i = a, END##i = b; i <= END##i; i++)
#define per(i, a, b) for (int i = a, END##i = b; i >= END##i; i--)

void Init();
void Solve();

signed main() {
    cin.sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    #ifdef FILE_INPUT
        freopen("input.in", "r", stdin);
    #endif

    int T = 1;
    // cin >> T;
    while (T--) {
        Init();
        Solve();
    }
    return 0;
}

using LL = long long;
using ULL = unsigned long long;

const int Mod = 1e9 + 7;
const int Inf = 0x3f3f3f3f;
const LL InfLL = 0x3f3f3f3f3f3f3f3f;

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

void Init() {
}

void Solve() {
    while (cin >> n, n) {
        rep(i, 1, n) cin >> a[i];
        int ans = 0;
        rep(i, 1, n) {
            f[i] = a[i];
            rep(j, 1, i - 1) if (a[i] > a[j]) {
                f[i] = max(f[i], f[j] + a[i]);
            }
            ans = max(ans, f[i]);
        }
        cout << ans << "\n";
    }
}

上面的代码时间复杂度是 \(O(n^2)\) 的,对于 \(n=10^5\) 时明显过不去,我们可以利用线段树来进行优化,从而将时间复杂度变为 \(O(n\log_2n)\),当然,线段树也可以优化 LIS 问题(虽然没必要,用二分就行)。

将这一行优化成 \(\log_2n\)

rep(j, 1, i - 1) if (a[i] > a[j]) {
	f[i] = max(f[i], f[j] + a[i]);
}

代码:

// #define FILE_INPUT
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define rep(i, a, b) for (int i = a, END##i = b; i <= END##i; i++)
#define per(i, a, b) for (int i = a, END##i = b; i >= END##i; i--)

void Init();
void Solve();

signed main() {
    cin.sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    #ifdef FILE_INPUT
        freopen("input.in", "r", stdin);
    #endif

    int T = 1;
    // cin >> T;
    while (T--) {
        Init();
        Solve();
    }
    return 0;
}

using LL = long long;
using ULL = unsigned long long;

const int Mod = 1e9 + 7;
const int Inf = 0x3f3f3f3f;
const LL InfLL = 0x3f3f3f3f3f3f3f3f;

const int N = 1010;
int n, f[N], a[N], rk[N], tot;

#define lc (p << 1)
#define rc (p << 1 | 1)
int tree[N << 2], tag[N << 2];
void pushdown(int p) {
    if (tag[p] != -1) {
        tree[lc] = max(tree[lc], tag[p]);
        tag[lc] = max(tag[lc], tag[p]);
        tree[rc] = max(tree[rc], tag[p]);
        tag[rc] = max(tag[rc], tag[p]);
        tag[p] = -1;
    }
}
void pushup(int p) {
    tree[p] = max(tree[lc], tree[rc]);
}
void update(int p, int L, int R, int l, int r, int d) {
    if (l <= L && R <= r) {
        tree[p] = max(tree[p], d);
        tag[p] = max(tag[p], d);
        return;
    }
    pushdown(p);
    int Mid = L + R >> 1;
    if (l <= Mid) update(lc, L, Mid, l, r, d);
    if (r > Mid) update(rc, Mid + 1, R, l, r, d);
    pushup(p);
}
int query(int p, int L, int R, int x) {
    if (L == x && R == x) return tree[p];
    pushdown(p);
    int Mid = L + R >> 1;
    if (x <= Mid) return query(lc, L, Mid, x);
    return query(rc, Mid + 1, R, x);
}

void Init() {
}

void Solve() {
    while (cin >> n, n) {
        tot = 0;
        memset(tree, 0, sizeof(tree));
        memset(tag, -1, sizeof(tag));
        rep(i, 1, n) {
            cin >> a[i];
            rk[++tot] = a[i];
        }
        sort(rk + 1, rk + tot + 1);
        tot = unique(rk + 1, rk + tot + 1) - rk - 1;
        int ans = 0;
        rep(i, 1, n) {
            int x = lower_bound(rk + 1, rk + tot + 1, a[i]) - rk;
            f[i] = query(1, 1, tot, x) + a[i];
            if (x + 1 <= tot) update(1, 1, tot, x + 1, tot, f[i]);
            ans = max(ans, f[i]);
        }
        cout << ans << "\n";
    }
}

我是不会告诉你我是为了凸显时间快才用离散化的 😃

posted @ 2025-02-02 17:28  wh2011  阅读(6)  评论(0)    收藏  举报