class Solution {
public:
int stoneGameII(vector<int>& piles) {
const int n = piles.size();
// dp[i][j] := max # of stones Alice can get w/ piles[i:] and M = j
dp.resize(n, vector<int>(n));
// suffixSum[i] := sum of piles[i:]
suffixSum = piles;
for (int i = n - 2; i >= 0; --i)
suffixSum[i] += suffixSum[i + 1];
return stoneGameII(0, 1);
}
private:
vector<vector<int>> dp;
vector<int> suffixSum;
int stoneGameII(int i, int M) {
if (i + 2 * M >= dp.size())
return suffixSum[i];
if (dp[i][M])
return dp[i][M];
int opponent = suffixSum[i];
for (int X = 1; X <= 2 * M; ++X)
opponent = min(opponent, stoneGameII(i + X, max(M, X)));
return dp[i][M] = suffixSum[i] - opponent;
}
};