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.
You do not need to check every pair during the DP. If the chosen indices are , it is enough to make every consecutive pair compatible.
Let be the best total weight of a valid selection whose last chosen index is . A previous last index may transition to exactly when
So the transition is where simultaneously and . The annoying part is just finding this maximum quickly.
Sweep from left to right. Call an earlier index active once ; from that moment onward, its can be inserted into a data structure keyed by .
Use a Fenwick tree storing prefix maximums. Schedule index to be inserted at time . At time , insert newly active indices, query the prefix ending at , and add . This gives per test case.
The condition looks global because it mentions every pair of chosen assignments. Fortunately, the global part collapses into a local one.
Suppose the chosen indices are
Assume every consecutive pair is valid. Consider any nonconsecutive pair .
Because lies between them,
Similarly, using the last gap before ,
Therefore so that pair is valid too. Thus it is enough to ensure compatibility between consecutive selected assignments.
That turns the problem into finding a maximum-weight path through indices from left to right.
Define as the maximum total weight of a valid selection whose rightmost chosen assignment is .
If is the previous chosen index, compatibility requires
This is equivalent to satisfying both and
Rearranging them gives and
Since all values are integers, the second inequality becomes
Hence
If no such exists, the best selection ending at contains only , so .
A quadratic implementation would inspect every earlier . That is obviously dead on arrival for , so we need to separate the two restrictions.
Sweep from left to right.
The restriction becomes permanently true starting at
Call active from that time onward. When computing , we schedule index to be activated at time . If this time is larger than , it can never be used by any later assignment and does not need to be scheduled.
At the start of step , every active index already satisfies the first transition restriction. Among those indices, we still need the maximum with
That is a prefix-maximum query by index.
A Fenwick tree is usually introduced for sums, but its update/query structure works just as well for monotone maximums:
update(i, value) records that position has value value;query(r) returns the maximum value among positions through .We never remove active indices, so maximum updates are perfect here.
For each position :
A query with simply returns , representing starting a new selection at .
We prove by induction over that is the best score of any valid selection ending at .
For a selection containing only , the score is , which the transition can always produce because the empty-prefix value is .
Now consider a valid selection ending at with some previous chosen index . Since and are consecutive in that selection, they must satisfy and . Therefore is active when step begins and lies inside the queried Fenwick prefix. By the induction hypothesis, is the best score ending at , so the algorithm considers a score at least as large as this selection's prefix plus .
Conversely, every index returned by the query is active, hence satisfies , and is inside the queried prefix, hence satisfies . Thus and are compatible. Appending to an optimal selection ending at creates a valid selection, because checking consecutive chosen indices is sufficient.
So the transition considers exactly all valid possibilities, and is correct. The final answer is with also implicitly allowed for the empty subset.
Each index is inserted into the Fenwick tree at most once and causes one prefix query.
Across all test cases, the total is at most .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct FenwickMax {
int n;
vector<ll> bit;
FenwickMax(int n) : n(n), bit(n + 1, 0) {}
void update(int i, ll value) {
for (; i <= n; i += i & -i)
bit[i] = max(bit[i], value);
}
ll query(int i) const {
ll result = 0;
for (; i > 0; i -= i & -i)
result = max(result, bit[i]);
return result;
}
};
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<ll> a(n + 1), dp(n + 1);
for (int i = 1; i <= n; ++i)
cin >> a[i];
vector<vector<int>> activate(n + 1);
FenwickMax fw(n);
ll answer = 0;
for (int j = 1; j <= n; ++j) {
for (int i : activate[j])
fw.update(i, dp[i]);
ll bound = (ll)j - a[j] - 1;
ll best = fw.query(bound > 0 ? (int)bound : 0);
dp[j] = best + a[j];
answer = max(answer, dp[j]);
ll when = (ll)j + a[j] + 1;
if (when <= n)
activate[(int)when].push_back(j);
}
cout << answer << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct FenwickMax {
int n;
vector<ll> bit;
FenwickMax(int n) : n(n), bit(n + 1, 0) {}
void update(int i, ll value) {
for (; i <= n; i += i & -i)
bit[i] = max(bit[i], value);
}
ll query(int i) const {
ll result = 0;
for (; i > 0; i -= i & -i)
result = max(result, bit[i]);
return result;
}
};
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<ll> a(n + 1), dp(n + 1);
for (int i = 1; i <= n; ++i)
cin >> a[i];
vector<vector<int>> activate(n + 1);
FenwickMax fw(n);
ll answer = 0;
for (int j = 1; j <= n; ++j) {
for (int i : activate[j])
fw.update(i, dp[i]);
ll bound = (ll)j - a[j] - 1;
ll best = fw.query(bound > 0 ? (int)bound : 0);
dp[j] = best + a[j];
answer = max(answer, dp[j]);
ll when = (ll)j + a[j] + 1;
if (when <= n)
activate[(int)when].push_back(j);
}
cout << answer << '\n';
}
}