<p>You have <code>n</code> dice, and each dice has <code>k</code> faces numbered from <code>1</code> to <code>k</code>.</p>

<p>Given three integers <code>n</code>, <code>k</code>, and <code>target</code>, return <em>the number of possible ways (out of the </em><code>k<sup>n</sup></code><em> total ways) </em><em>to roll the dice, so the sum of the face-up numbers equals </em><code>target</code>. Since the answer may be too large, return it <strong>modulo</strong> <code>10<sup>9</sup> + 7</code>.</p>

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

<pre>
<strong>Input:</strong> n = 1, k = 6, target = 3
<strong>Output:</strong> 1
<strong>Explanation:</strong> You throw one die with 6 faces.
There is only one way to get a sum of 3.
</pre>

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

<pre>
<strong>Input:</strong> n = 2, k = 6, target = 7
<strong>Output:</strong> 6
<strong>Explanation:</strong> You throw two dice, each with 6 faces.
There are 6 ways to get a sum of 7: 1+6, 2+5, 3+4, 4+3, 5+2, 6+1.
</pre>

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

<pre>
<strong>Input:</strong> n = 30, k = 30, target = 500
<strong>Output:</strong> 222616187
<strong>Explanation:</strong> The answer must be returned modulo 10<sup>9</sup> + 7.
</pre>

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

<ul>
	<li><code>1 &lt;= n, k &lt;= 30</code></li>
	<li><code>1 &lt;= target &lt;= 1000</code></li>
</ul>

class Solution {
    int diceThrowsHelper(int d, int f, int s, int t, vector<vector<int>>& dp) {
        if (d == 0 && t == s)
            return 1;
        if (d == 0 && t < s)
            return 0;
        if (d == 0 && t > s)
            return 0;

        if (dp[d][t] != -1) {
            return dp[d][t];
        }

        long long int ways = 0;
        for (int i = 1; i <= f && d > 0; i++) {
            ways =
                (ways + diceThrowsHelper(d - 1, f, s, t + i, dp)) % 1000000007;
            dp[d][t] = ways;
        }
        return dp[d][t];
    }

    int usingMemoisation(int n, int k, int target,
                         vector<vector<long long int>>& dp) {
        if (n < 0)
            return 0;
        if (n == 0 && target == 0)
            return 1;
        if (n == 0 && target != 0)
            return 0;
        if (n != 0 && target == 0)
            return 0;

        if (dp[n][target] != -1) {
            return dp[n][target];
        }
        long long int ans = 0;
        for (int i = 1; i <= k; i++) {
            long long int recAns = 0;
            if (target - i >= 0) {
                recAns = usingMemoisation(n - 1, k, target - i, dp);
                recAns = recAns % 1000000007;
                ans = (ans + recAns) % 1000000007;
            }
        }
        dp[n][target] = ans;
        return dp[n][target];
    }

    int usingTabulation(int n, int k, int target) {
        vector<vector<long long int>> dp(n + 1,
                                         vector<long long int>(target + 1, 0));
        dp[0][0] = 1;

        for (int index = 1; index <= n; index++) {
            for (int j = 1; j <= target; j++) {

                long long int ans = 0;
                for (int i = 1; i <= k; i++) {
                    long long int recAns = 0;
                    if (j - i >= 0) {
                        recAns = dp[index - 1][j - i];
                        recAns = recAns % 1000000007;
                        ans = (ans + recAns) % 1000000007;
                    }
                }
                dp[index][j] = ans;
            }
        }
        return dp[n][target];
    }

    int spaceOptmization(int n, int k, int target) {
        vector<int> prev(target + 1, 0);
        vector<int> curr(target + 1, 0);
        prev[0] = 1;
        for (int index = 1; index <= n; index++) {
            for (int j = 1; j <= target; j++) {

                long long int ans = 0;
                for (int i = 1; i <= k; i++) {
                    long long int recAns = 0;
                    if (j - i >= 0) {
                        recAns = prev[j - i];
                        recAns = recAns % 1000000007;
                        ans = (ans + recAns) % 1000000007;
                    }
                }
                curr[j] = ans;
            }
            prev = curr;
        }
        return prev[target];
    }

public:
    int numRollsToTarget(int n, int k, int target) {
        // vector<vector<long long int>> dp(n + 1,vector<long long int>(target + 1, -1));
        // return usingMemoisation(n,k,target,dp);
        // return usingTabulation(n,k,target);
        // return spaceOptmization(n, k, target);

        int sm=n*k; // This is the maximum sum of 'd' dice with 'f' faces.
    
        vector<vector<int>>dp(n+1, vector<int>(sm+1, -1));
        return diceThrowsHelper(n, k, target, 0, dp);
    }
};
9200