Problem:
Score : 100 points

Problem Statement

Taro and Jiro will play the following game against each other.

Initially, they are given a sequence a = (a_1, a_2, \ldots, a_N).
Until a becomes empty, the two players perform the following operation alternately, starting from Taro:

Remove the element at the beginning or the end of a. The player earns x points, where x is the removed element.

Let X and Y be Taro's and Jiro's total score at the end of the game, respectively.
Taro tries to maximize X - Y, while Jiro tries to minimize X - Y.

Assuming that the two players play optimally, find the resulting value of X - Y.

Constraints

All values in input are integers.

1 \leq N \leq 3000

1 \leq a_i \leq 10^9

Input

Input is given from Standard Input in the following format:

N
a_1 a_2 \ldots a_N

Output

Print the resulting value of X - Y, assuming that the two players play optimally.

Sample Input 1

4
10 80 90 30

Sample Output 1

10

The game proceeds as follows when the two players play optimally (the element being removed is written bold):

Taro: (10, 80, 90, 30) → (10, 80, 90)

Jiro: (10, 80, 90) → (10, 80)

Taro: (10, 80) → (10)

Jiro: (10) → ()

Here, X = 30 + 80 = 110 and Y = 90 + 10 = 100.

Sample Input 2

3
10 100 10

Sample Output 2

-80

The game proceeds, for example, as follows when the two players play optimally:

Taro: (10, 100, 10) → (100, 10)

Jiro: (100, 10) → (10)

Taro: (10) → ()

Here, X = 10 + 10 = 20 and Y = 100.

Sample Input 3

1
10

Sample Output 3

10

Sample Input 4

10
1000000000 1 1000000000 1 1000000000 1 1000000000 1 1000000000 1

Sample Output 4

4999999995

The answer may not fit into a 32-bit integer type.

Sample Input 5

6
4 2 9 7 1 5

Sample Output 5

2

The game proceeds, for example, as follows when the two players play optimally:

Taro: (4, 2, 9, 7, 1, 5) → (4, 2, 9, 7, 1)

Jiro: (4, 2, 9, 7, 1) → (2, 9, 7, 1)

Taro: (2, 9, 7, 1) → (2, 9, 7)

Jiro: (2, 9, 7) → (2, 9)

Taro: (2, 9) → (2)

Jiro: (2) → ()

Here, X = 5 + 1 + 9 = 15 and Y = 4 + 7 + 2 = 13.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)


//https://atcoder.jp/contests/dp/tasks/dp_l

#include <bits/stdc++.h>
#include <limits.h>
#include <algorithm>  


#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;

#define imie(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "

typedef long long int ll;

const int precision = 16;
const int modulo =  1000000007; // 10^9 + 7
using ll = long long;
const double EPS = 1e-9;

pair<ll, ll> recSolve2(int l, int r, vector<int> & seq, bool player) {
	if(l > r) return {0,0};

	if(player == false) {  //taro

		auto fleft = recSolve2(l + 1, r, seq, true);
		auto fRight = recSolve2(l, r - 1, seq, true);

		if(seq[l] + fleft.first - fleft.second >
		seq[r] + fRight.first - fleft.second) {
			return {seq[l] + fleft.first, fleft.second};
		}  else {
			return {seq[r] + fRight.first, fRight.second};
		}
	} else {
		auto fleft = recSolve2(l + 1, r, seq, false);
		auto fRight = recSolve2(l, r - 1, seq, false);

		if(fleft.first - seq[l] - fleft.second <
		fRight.first - seq[r] - fRight.second) {
			return {fleft.first, seq[l] + fleft.second};
		} else {
			return {fRight.first, seq[r] + fRight.second};
		}
	}
}


ll recSolve(int l, int r, vector<int> & seq, vector<vector<ll>> & memo) {
	if(l > r) return 0;
	if(memo[l][r] != -1) return memo[l][r];

	ll leftTaken = seq[l] + min(recSolve(l + 2, r, seq, memo), 
		recSolve(l + 1, r - 1, seq, memo));
	ll rightTaken = seq[r] + min(recSolve(l + 1, r - 1, seq, memo), 
		recSolve(l, r - 2, seq, memo));

	memo[l][r] =  max(leftTaken, rightTaken);
	return memo[l][r];
}

ll solveDeque() {
	int n; cin >> n;
	vector<int> seq(n);
	for(auto & v : seq) {
		cin >> v;
	}

	vector<vector<ll>> memo(3000, vector<ll>(3000, -1));

	ll taroAcc = recSolve(0, n - 1, seq, memo);
	ll acc = accumulate(seq.begin(), seq.end(), 0l);
	ll jiroAcc = acc - taroAcc;

	return taroAcc - jiroAcc;
}

ll solveDequeDP() {
	int n; cin >> n;
	vector<int> seq(n);
	for(auto & v : seq) {
		cin >> v;
	}
	
	
	vector<vector<ll>> dp(n + 1, vector<ll>(n + 1, 0));

	for(auto delta = 0; delta < n; ++delta) {
		for(auto l = 0; l < n - delta; ++l) {
			auto r = l + delta;
			if(l > r) continue;

			if(l == r){
				dp[l][r] = seq[l];
			} else {
				auto leftTaken = seq[l] + min(dp[l + 2][r], dp[l + 1][r - 1]);
				auto rightTaken = seq[r] + min(dp[l][r - 2], dp[l + 1][r - 1]);

				dp[l][r] = max(leftTaken, rightTaken);
			}
		}
	}

	ll taroAcc = dp[0][n - 1];
	ll acc = accumulate(seq.begin(), seq.end(), 0l);
	ll jiroAcc = acc - taroAcc;
	return taroAcc - jiroAcc;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	cout.precision(precision);
	cout.setf(ios_base::fixed);

	auto ret = solveDequeDP();
	cout << ret << endl;
	
	return 0;
}