Chixiyu's blog

By Chixiyu, history, 42 hours ago, In English

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:

$$$ j=max(p\_dp[0...i-1])\\ p\_dp[i]=max(p\_dp[i],p\_dp[j]+a[i]), a[i]>0\\ a[i]=a[n-i+1],i=[1,n]\\ s\_dp[i]=max(s\_dp[i],s\_dp[j]-a[i]), a[i]<0\\ $$$

Important constraints:

$$$ p\_dp[i]=NEGINF,a[i]<0\\ s\_dp[i]=NEGINF,a[i]>0 $$$

The third way combines prefix and suffix:

$$$ combined\_ans=max(combined\_ans,p\_dp[i]+s\_dp[n-i]) $$$

Final answer is maximum of all three approaches:

$$$ ans=max(p\_dp[n],s\_dp[n],combined\_ans) $$$

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;
}
Tags dp
  • Vote: I like it
  • -1
  • Vote: I do not like it

»
41 hour(s) ago, # |
  Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by Chixiyu (previous revision, new revision, compare).

»
35 hours ago, # |
  Vote: I like it +1 Vote: I do not like it

Correct but too tedious. Just calculate the prefix sum and the suffix sum of the positive and negetive numbers.

306469506

  • »
    »
    17 hours ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    You're right, 17 lines of code and it's done.