<p>You are given an <code>m x n</code> integer matrix <code>points</code> (<strong>0-indexed</strong>). Starting with <code>0</code> points, you want to <strong>maximize</strong> the number of points you can get from the matrix.</p>

<p>To gain points, you must pick one cell in <strong>each row</strong>. Picking the cell at coordinates <code>(r, c)</code> will <strong>add</strong> <code>points[r][c]</code> to your score.</p>

<p>However, you will lose points if you pick a cell too far from the cell that you picked in the previous row. For every two adjacent rows <code>r</code> and <code>r + 1</code> (where <code>0 &lt;= r &lt; m - 1</code>), picking cells at coordinates <code>(r, c<sub>1</sub>)</code> and <code>(r + 1, c<sub>2</sub>)</code> will <strong>subtract</strong> <code>abs(c<sub>1</sub> - c<sub>2</sub>)</code> from your score.</p>

<p>Return <em>the <strong>maximum</strong> number of points you can achieve</em>.</p>

<p><code>abs(x)</code> is defined as:</p>

<ul>
	<li><code>x</code> for <code>x &gt;= 0</code>.</li>
	<li><code>-x</code> for <code>x &lt; 0</code>.</li>
</ul>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong><strong> </strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/07/12/screenshot-2021-07-12-at-13-40-26-diagram-drawio-diagrams-net.png" style="width: 300px; height: 300px;" />
<pre>
<strong>Input:</strong> points = [[1,2,3],[1,5,1],[3,1,1]]
<strong>Output:</strong> 9
<strong>Explanation:</strong>
The blue cells denote the optimal cells to pick, which have coordinates (0, 2), (1, 1), and (2, 0).
You add 3 + 5 + 3 = 11 to your score.
However, you must subtract abs(2 - 1) + abs(1 - 0) = 2 from your score.
Your final score is 11 - 2 = 9.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/07/12/screenshot-2021-07-12-at-13-42-14-diagram-drawio-diagrams-net.png" style="width: 200px; height: 299px;" />
<pre>
<strong>Input:</strong> points = [[1,5],[2,3],[4,2]]
<strong>Output:</strong> 11
<strong>Explanation:</strong>
The blue cells denote the optimal cells to pick, which have coordinates (0, 1), (1, 1), and (2, 0).
You add 5 + 3 + 4 = 12 to your score.
However, you must subtract abs(1 - 1) + abs(1 - 0) = 1 from your score.
Your final score is 12 - 1 = 11.
</pre>

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

<ul>
	<li><code>m == points.length</code></li>
	<li><code>n == points[r].length</code></li>
	<li><code>1 &lt;= m, n &lt;= 10<sup>5</sup></code></li>
	<li><code>1 &lt;= m * n &lt;= 10<sup>5</sup></code></li>
	<li><code>0 &lt;= points[r][c] &lt;= 10<sup>5</sup></code></li>
</ul>

class Solution {
public:
    long long util (vector<vector<int>> &p, int row, int lastCol, vector<vector<int>> &dp) {
        if (row == p.size()) return 0;

        if(dp[row][lastCol+1]!=-1) return dp[row][lastCol+1];
        long long ans=0;
        for (int i=0; i<p[0].size(); i++) {
            long long curr = 0;
            if (lastCol == -1) {
                curr = p[row][i] + util(p, row+1, i, dp);
            }else{
                curr = p[row][i]-abs(i-lastCol)+util(p, row+1, i, dp);
            }
            ans = max(ans, curr);
        }
        dp[row][lastCol+1] = ans;
        return dp[row][lastCol+1];
    }
    long long maxPoints (vector<vector<int>>& p) {
   int rows = p.size();
    int cols = p[0].size();

    // dp[row][col] represents the max points you can get from row 'row' and column 'col'
    vector<vector<long long>> dp(rows, vector<long long>(cols, 0));

    // Base case: For the last row, the points are just the values in the last row
    for (int col = 0; col < cols; col++) {
        dp[rows-1][col] = p[rows-1][col];
    }

    // Fill the dp table in bottom-up fashion
    for (int row = rows - 2; row >= 0; row--) {
        // We need two arrays to track max from left to right and right to left
        vector<long long> left(cols, 0), right(cols, 0);
        
        // left[i] will store the max points if we come from the left side to i
        left[0] = dp[row+1][0];
        for (int i = 1; i < cols; i++) {
            left[i] = max(left[i-1] - 1, dp[row+1][i]);
        }

        // right[i] will store the max points if we come from the right side to i
        right[cols-1] = dp[row+1][cols-1];
        for (int i = cols - 2; i >= 0; i--) {
            right[i] = max(right[i+1] - 1, dp[row+1][i]);
        }

        // Now fill the dp[row][col] based on left and right arrays
        for (int col = 0; col < cols; col++) {
            dp[row][col] = p[row][col] + max(left[col], right[col]);
        }
    }

    // The answer will be the max value in the first row
    long long ans = 0;
    for (int col = 0; col < cols; col++) {
        ans = max(ans, dp[0][col]);
    }
    return ans;
    }
};
133756