Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Think of every item as a point where is its position in Alice's list and is its position in Bob's list. At any moment Alice can remove the alive point with smallest , and Bob can remove the alive point with smallest .
If Alice eventually buys item , then every item before in Alice's order must disappear earlier. Some of them can be bought by Alice too, but any skipped one must be removable by Bob before .
Process Alice's order from left to right. When deciding whether Alice can buy , look at the last Alice-bought item before it. Every item skipped between them must appear before in Bob's order.
Let be the Bob-position of . If Alice buys positions then in Alice-order, the transition is legal exactly when .
For each , find , the nearest previous index with . Then can follow any bought position with . Use a monotonic stack for and a segment tree for range-max DP.
Rename the objects into points.
For object :
Alice always removes the alive object with minimum . Bob always removes the alive object with minimum . We choose who moves each turn.
Now list objects in Alice-order:
and define
So is the Bob-position of the object at Alice-position .
The real constraint
Suppose Alice buys .
Before that, every object before in Alice's order must already be gone. If Alice did not buy one of those earlier objects, then Bob must have bought it.
Now suppose Alice buys and later buys , where , and buys nothing from positions .
All those skipped objects must be cleared by Bob before Alice can buy .
Bob can clear a skipped object before touching only if
If , Bob would reach first. Then Bob would buy , and Alice's plan is dead. Brutal, but simple.
So the transition is legal exactly when
For the first object Alice buys, pretend .
DP
Let
For each , define as the nearest previous index with
If no such index exists, .
Why does this help? Any transition into must start from some previous Alice-bought position such that all skipped positions after have Bob-position less than . The nearest earlier blocker with Bob-position greater than is , so we need
Therefore:
The handles starting fresh, and it also prevents negative baggage from coming along for the ride.
The answer is
because Alice may buy nothing.
Computing
Use a monotonic decreasing stack of indices by .
When processing :
Each index is pushed and popped once.
Range maximum
The recurrence needs
Use a segment tree over Alice positions. Put at position .
For every :
Correctness
Any valid strategy gives a legal DP path. Between two consecutive Alice-bought positions and , every skipped object must be removed by Bob before . That requires every skipped object's Bob-position to be less than , so .
Any DP path is achievable. For each transition , all skipped objects between them have Bob-position less than . After Alice buys , let Bob move until those skipped objects are gone; Bob will remove them before . Then Alice buys .
So the DP captures exactly the possible Alice sets, not vibes, not magic.
Complexity:
per test case, with memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct SegTree {
int n;
vector<ll> st;
SegTree(int sz = 0) { init(sz); }
void init(int sz) {
n = 1;
while (n < sz) n <<= 1;
st.assign(2 * n, LLONG_MIN / 4);
}
void update(int pos, ll val) {
pos += n;
st[pos] = max(st[pos], val);
for (pos >>= 1; pos; pos >>= 1) {
st[pos] = max(st[pos << 1], st[pos << 1 | 1]);
}
}
ll query(int l, int r) {
if (l > r) return LLONG_MIN / 4;
l += n;
r += n;
ll res = LLONG_MIN / 4;
while (l <= r) {
if (l & 1) res = max(res, st[l++]);
if (!(r & 1)) res = max(res, st[r--]);
l >>= 1;
r >>= 1;
}
return res;
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> v(n + 1);
for (int i = 1; i <= n; i++) cin >> v[i];
vector<int> a(n + 1), b(n + 1), posB(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
cin >> b[i];
posB[b[i]] = i;
}
vector<int> p(n + 1);
for (int i = 1; i <= n; i++) p[i] = posB[a[i]];
SegTree seg(n + 1);
seg.update(0, 0);
vector<int> stk;
ll ans = 0;
for (int i = 1; i <= n; i++) {
while (!stk.empty() && p[stk.back()] < p[i]) stk.pop_back();
int L = stk.empty() ? 0 : stk.back();
ll best = seg.query(L, i - 1);
ll dp = v[a[i]] + max(0LL, best);
ans = max(ans, dp);
seg.update(i, dp);
stk.push_back(i);
}
cout << ans << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct SegTree {
int n;
vector<ll> st;
SegTree(int sz = 0) { init(sz); }
void init(int sz) {
n = 1;
while (n < sz) n <<= 1;
st.assign(2 * n, LLONG_MIN / 4);
}
void update(int pos, ll val) {
pos += n;
st[pos] = max(st[pos], val);
for (pos >>= 1; pos; pos >>= 1) {
st[pos] = max(st[pos << 1], st[pos << 1 | 1]);
}
}
ll query(int l, int r) {
if (l > r) return LLONG_MIN / 4;
l += n;
r += n;
ll res = LLONG_MIN / 4;
while (l <= r) {
if (l & 1) res = max(res, st[l++]);
if (!(r & 1)) res = max(res, st[r--]);
l >>= 1;
r >>= 1;
}
return res;
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> v(n + 1);
for (int i = 1; i <= n; i++) cin >> v[i];
vector<int> a(n + 1), b(n + 1), posB(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
cin >> b[i];
posB[b[i]] = i;
}
vector<int> p(n + 1);
for (int i = 1; i <= n; i++) p[i] = posB[a[i]];
SegTree seg(n + 1);
seg.update(0, 0);
vector<int> stk;
ll ans = 0;
for (int i = 1; i <= n; i++) {
while (!stk.empty() && p[stk.back()] < p[i]) stk.pop_back();
int L = stk.empty() ? 0 : stk.back();
ll best = seg.query(L, i - 1);
ll dp = v[a[i]] + max(0LL, best);
ans = max(ans, dp);
seg.update(i, dp);
stk.push_back(i);
}
cout << ans << '\n';
}
return 0;
}