Problem p02716 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
using namespace std;

int main() {
  int64_t N;
  cin >> N;
  vector<int64_t> A(N);
  for (int64_t i = 0; i < N; i++) {
    cin >> A[i];
  }

  constexpr int64_t STATE_NUM = 3;

  // また、直前で選んだかどうかで更に2倍の状態
  // dp[i][j][k] := iまでで、選んだ数がj = MIN or MAXであり、k =
  // (直前で選んだ)場合の最大値
  vector<vector<vector<int64_t>>> dp(
      N + 1,
      vector<vector<int64_t>>(STATE_NUM, vector<int64_t>(2, LLONG_MIN / 2)));
  dp[0][0][0] = 0;

  for (int64_t i = 0; i < N; i++) {
    // 選んでいる数として可能な最小値、最大値を計算
    const int64_t curr_min_num = max(N / 2 - (N - i + 1) / 2, (int64_t)0);
    const int64_t next_min_num = N / 2 - (N - i) / 2;

    // 状態がSTATE_NUM×2通り
    for (int64_t j = 0; j < STATE_NUM; j++) {
      for (int64_t k : {0, 1}) {
        // 遷移が2通り
        for (int64_t add : {0, 1}) {
          if (k == 1 && add == 1) {
            // 連続して選ぶのは不可
            continue;
          }
          const int64_t num = curr_min_num + j + add;
          const int64_t diff = num - next_min_num;

          if (0 <= diff && diff < STATE_NUM) {
            dp[i + 1][diff][add] =
                max(dp[i + 1][diff][add], dp[i][j][k] + A[i] * add);
          }
        }
      }
    }
  }

  cout << max({dp[N][0][0], dp[N][0][1]}) << endl;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;

int main() {
  int64_t N;
  cin >> N;
  vector<int64_t> A(N);
  for (int64_t &a : A) {
    cin >> a;
  }

  function<int64_t(int64_t, int64_t, int64_t)> solve = [&](int64_t l, int64_t r,
                                                           int64_t num) {
    if (num == 1) {
      int64_t result = INT_MIN;
      for (int64_t i = l; i < r; i++) {
        result = max(result, A[i]);
      }
      return result;
    }
    if (num == 0) {
      return (int64_t)0;
    }
    if (num < 0 || (r - l + 1) / 2 < num) {
      return (int64_t)INT_MIN;
    }
    assert(r > l);
    //        if ((r - l + 1) / 2 == num) {
    //            if ((r - l) % 2 == 0) {
    //                int64_t even_sum = 0;
    //                int64_t odd_sum = 0;
    //                for (int64_t i = l; i < r; i++) {
    //                    ((i - l) % 2 == 0 ? even_sum : odd_sum) += A[i];
    //                }
    //                return max(even_sum, odd_sum);
    //            } else {
    //                int64_t result = 0;
    //                for (int64_t i = l; i < r; i += 2) {
    //                    result += A[i];
    //                }
    //                return result;
    //            }
    //        }

    // 中央から選ぶ/選ばないときの最良値
    int64_t result = INT_MIN;

    // 中央
    int64_t mid = (l + r) / 2;

    // 中央から選ぶ
    {
      for (int64_t left_num = (mid - 1 - l + 1) / 2; left_num >= 0;
           left_num--) {
        result = max(result, A[mid] + solve(l, mid - 1, left_num) +
                                 solve(mid + 2, r, num - 1 - left_num));
      }
    }

    // 中央から選ばない
    {
      for (int64_t left_num = (mid - l + 1) / 2; left_num >= 0; left_num--) {
        int64_t right_num = num - left_num;
        result =
            max(result, solve(l, mid, left_num) + solve(mid + 1, r, right_num));
      }
    }

    return result;
  };

  cout << solve(0, N, N / 2) << endl;
}