<p>You are given <code>n</code> balloons, indexed from <code>0</code> to <code>n - 1</code>. Each balloon is painted with a number on it represented by an array <code>nums</code>. You are asked to burst all the balloons.</p>

<p>If you burst the <code>i<sup>th</sup></code> balloon, you will get <code>nums[i - 1] * nums[i] * nums[i + 1]</code> coins. If <code>i - 1</code> or <code>i + 1</code> goes out of bounds of the array, then treat it as if there is a balloon with a <code>1</code> painted on it.</p>

<p>Return <em>the maximum coins you can collect by bursting the balloons wisely</em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> nums = [3,1,5,8]
<strong>Output:</strong> 167
<strong>Explanation:</strong>
nums = [3,1,5,8] --&gt; [3,5,8] --&gt; [3,8] --&gt; [8] --&gt; []
coins =  3*1*5    +   3*5*8   +  1*3*8  + 1*8*1 = 167</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> nums = [1,5]
<strong>Output:</strong> 10
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>n == nums.length</code></li>
	<li><code>1 &lt;= n &lt;= 300</code></li>
	<li><code>0 &lt;= nums[i] &lt;= 100</code></li>
</ul>

class Solution {
public:
static inline int64_t maxi(int64_t a, int64_t b) {
  return a < b ? b : a;
}

static inline int64_t maxRemoveCounterIntervals(vector<int>& x, int32_t i, int32_t j, int32_t ii, int32_t jj) {
  if(ii == jj) {
    return x[i] * x[j] * x[ii];
  }
  if(ii != i && jj != j) {
    return maxi(x[ii] * x[jj] * x[i] + x[jj] * x[i] * x[j],
                x[ii] * x[jj] * x[j] + x[ii] * x[i] * x[j]);
  }
  if(ii == i && jj != j) {
    return x[jj] * x[i] * x[j];
  }
  if(jj == j && ii != i) {
    return x[ii] * x[i] * x[j];
  }
  return 0;
}

int64_t maxValue(vector<int>& nums, int32_t left, int32_t right, int64_t dp[][304]) {
  if(right - left <= 1) {
    return 0;
  }
  if(dp[left][right]) {
    return dp[left][right];
  }
  int64_t maxValueResponse = 0;
  for(int32_t i = left + 1; i <= right - 1; i++) {
    maxValueResponse = maxi(maxValueResponse, maxValue(nums, left, i, dp) + maxValue(nums, i, right, dp) + maxRemoveCounterIntervals(nums, left, right, i, i));
  }
  for(int32_t i = left; i <= right - 1; i++) {
    maxValueResponse = maxi(maxValueResponse, maxValue(nums, left, i, dp) + maxValue(nums, i + 1, right, dp) + maxRemoveCounterIntervals(nums, left, right, i, i + 1));
  }
  dp[left][right] = maxValueResponse;

  return maxValueResponse;
}

int maxCoins(vector<int>& nums) {
  int64_t dp[304][304] = {0};
  nums.insert(nums.begin(), 1);
  nums.push_back(1);
  int64_t value = maxValue(nums, 0, nums.size() - 1, dp);
  return value;
}
};
10600