CF2064C: Remove the Ends
Problem — C — Codeforces 2064C - Remove the Ends
Approach 1 (TLE): Memoized Search
Direct memoized search using unordered_map
. We need to combine l
and r
states into a single long long
for storage. Unfortunately, TLEs on test case 5.
// Note: TLE
#include <bits/stdc++.h>
using namespace std;
static inline long long encodeState(int l, int r) {
return ((long long)l << 32) | (unsigned int)r;
}
unordered_map<long long, long long> dpMemo;
vector<int> a;
long long dp(int l, int r) {
if (l > r)
return 0;
long long key = encodeState(l, r);
if (dpMemo.count(key))
return dpMemo[key];
long long best = -LLONG_MAX / 2;
for (int i = l; i <= r; i++) {
if (a[i] > 0) {
best = max(best, (long long)a[i] + dp(i + 1, r));
} else if (a[i] < 0) {
best = max(best, (long long)(-a[i]) + dp(l, i - 1));
}
}
dpMemo[key] = best;
return best;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
a.resize(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
dpMemo.clear();
long long ans = dp(1, n);
cout << ans << "\n";
}
return 0;
}
Approach 2 (AC): Left-Right DP Merge
Let's look for patterns: - If array a
is all positive, maximize by taking left to right: $$$ans=\sum^n_{i=0}a_i$$$ - If all negative, take right to left - Or split: take [0,i] from left and [i+1,n] from right
We can use two DP arrays: p_dp
(prefix) and s_dp
(suffix). $$$p_dp[i]$$$ represents maximum answer taking positives from left up to position i:
Important constraints:
The third way combines prefix and suffix:
Final answer is maximum of all three approaches:
Code:
/*
* Created by: Chixiyu
* Date: 2025-02-17
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll NEG_INF = -1000000000000000000LL; // -1e18
void solve() {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
// prefix
vector<ll> prefix_dp(n + 1, NEG_INF);
ll prefix_ans;
ll prev_max = 0; // prevmax= max(a[0,i-1])
prefix_dp[0] = 0;
for (int i = 1; i <= n; i++) {
if (a[i] > 0) { // can prefix dp1
prefix_dp[i] = max(prefix_dp[i], a[i] + prev_max);
// update prev_max
prev_max = max(prev_max, prefix_dp[i]);
}
}
prefix_ans = prefix_dp[n];
// suffix
vector<ll> suffix_dp(n + 1, NEG_INF);
ll suffix_ans;
prev_max = 0;
// inverse the array
reverse(++a.begin(), a.end());
suffix_dp[0] = 0;
for (int i = 1; i <= n; i++) {
if (a[i] < 0) { // can suffix dp
suffix_dp[i] = max(suffix_dp[i], -a[i] + prev_max);
prev_max = max(prev_max, suffix_dp[i]);
}
}
suffix_ans = suffix_dp[n];
// calculate combined
ll combined_ans = NEG_INF;
for (int i = 0; i <= n; i++) {
ll left = prefix_dp[i];
ll right = 0;
if (i != n) {
right = suffix_dp[n - i];
}
combined_ans = max(combined_ans, left + right);
}
cout << max({prefix_ans, suffix_ans, combined_ans}) << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
Auto comment: topic has been updated by Chixiyu (previous revision, new revision, compare).
Correct but too tedious. Just calculate the prefix sum and the suffix sum of the positive and negetive numbers.
306469506
You're right, 17 lines of code and it's done.