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

//?????£???????????????????????£???????????°??±???????????¶???????????????.
//??????????????????????????°???DP
#include <algorithm>
#include <iostream>
#define int long long
using namespace std;

int n;
int a[2000];
int dp
    [2][2000]
    [2000]; // dp[2][l][r] :=
            // ????????????????????????????????¢([0]->IOI?????????,[1]->JOI??????)

int ioi(
    int l,
    int r); //???????????????????????£???????????????l??¨r,
            //?????????l??????????¨??????????????????¨?????????r?????????????????????l??¨r???????????????
int joi(int l, int r); //??±??????????????£???????????´?????????????????????l,
                       //r???????????????????????????????????????

int ioi(int l, int r) {
  if (dp[0][l][r] >= 0)
    return dp[0][l][r];
  if ((l + n - 1) % n == r) {
    return (dp[0][l][r] = 0);
  } else if (a[l] > a[r]) {
    return (dp[0][l][r] = joi((l + 1) % n, r));
  } else {
    return (dp[0][l][r] = joi(l, (r + n - 1) % n));
  }
}
int joi(int l, int r) {
  if (dp[1][l][r] >= 0)
    return dp[1][l][r];
  if ((l + n - 1) % n == r) {
    return (dp[1][l][r] = 0);
  }
  int u = ioi((l + 1) % n, r) + a[l];
  int v = ioi(l, (r + n - 1) % n) + a[r];
  return (dp[1][l][r] = max(u, v));
}

signed main() {
  int i;

  cin >> n;
  for (i = 0; i < n; i++)
    cin >> a[i];

  for (int l = 0; l < n; l++) {
    for (int r = 0; r < n; r++) {
      dp[0][l][r] = -1;
      dp[1][l][r] = -1;
    }
  }

  int ans = 0;
  for (i = 0; i < n; i++) {
    ans = max(ans, ioi((i + 1) % n, (i + n - 1) % n) + a[i]);
  }
  cout << ans << endl;
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
using namespace std;

int n;
long long a[2000], A[8000];
long long dp[2048][2048]; // dp[l][r]…0の並ぶ区間[l,r]
long long ans = 0;

void get_iniQ(int i, int &l, int &r, long long &num) {
  if (A[i + 1] > A[i - 1]) {
    l = i;
    r = i + 1;
  } else {
    l = i - 1;
    r = i;
  }
  num = A[i];
}

void dfs(int l, int r, long long num, int dep, int maxdep) {
  if (dp[l & 2047][r & 2047] > num || r - l + 1 > n + 1) {
    return;
  }
  if (dep > maxdep) {
    return;
  }

  dp[l & 2047][r & 2047] = num;
  ans = max(ans, num);

  // A[l-1]をJOI君が取る
  // A[l-2]かA[r+1]をIOIちゃんが取る
  if (A[l - 2] > A[r + 1])
    dfs(l - 2, r, num + A[l - 1], dep + 1, maxdep);
  else
    dfs(l - 1, r + 1, num + A[l - 1], dep + 1, maxdep);
  // A[r+1]をJOI君が取る
  // A[l-1]かA[r+2]をIOIちゃんが取る
  if (A[l - 1] > A[r + 2])
    dfs(l - 1, r + 1, num + A[r + 1], dep + 1, maxdep);
  else
    dfs(l, r + 2, num + A[r + 1], dep + 1, maxdep);
}

void random_permutation(int *per, int n) {
  int i;
  srand(252521);
  for (i = 0; i < n; i++) {
    int p;
    do {
      p = rand() % n;
    } while (per[p]);
    per[p] = i;
  }
}

signed main() {
  int i, j, k;
  cin >> n;
  // if( n > 300 )return 0;
  for (i = 0; i < n; i++) {
    cin >> a[i];
    A[i] = a[i];
    A[i + n] = a[i];
    A[i + 2 * n] = a[i];
    A[i + 3 * n] = a[i];
  }

  int per[2000] = {0};
  random_permutation(per, n);

  for (int maxdep = 1; maxdep <= n; maxdep++) {
    for (i = 0; i < n; i++) {
      int l, r;
      long long num;
      get_iniQ(per[i] + n, l, r, num);
      dfs(l, r, num, 0, maxdep);
    }
  }
  cout << ans << endl;
  return 0;
}