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";
}
}
我是不会告诉你我是为了凸显时间快才用离散化的 😃

浙公网安备 33010602011771号