You have n dice and each die has k faces numbered from 1 to k.
Given three integers n, k, and target, return the number of possible ways (out of thekntotal ways)to roll the dice so the sum of the face-up numbers equalstarget. Since the answer may be too large, return it modulo10^9 + 7.
Input:
n = 1, k = 6, target = 3
Output:
1
Explanation: You throw one die with 6 faces.
There is only one way to get a sum of 3.
Example 2:
1
2
3
4
5
6
Input:
n = 2, k = 6, target = 7
Output:
6
Explanation: 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.
Example 3:
1
2
3
4
5
Input:
n = 30, k = 30, target = 500
Output:
222616187
Explanation: The answer must be returned modulo 10^9 + 7.
We use recursion with memoization to count the number of ways to roll n dice with k faces to reach the target sum. For each die, we try all possible face values and recursively solve for the remaining dice and target.
classSolution {
public:int numRollsToTarget(int n, int k, int target) {
constint MOD =1e9+7;
vector<vector<int>> dp(n +1, vector<int>(target +1, -1));
returnhelper(n, k, target, dp, MOD);
}
private:int helper(int n, int k, int target, vector<vector<int>>& dp, int MOD) {
if (target <0) return0;
if (n ==0) return target ==0?1:0;
if (dp[n][target] !=-1) return dp[n][target];
int ans =0;
for (int i =1; i <= k; ++i) {
ans = (ans + helper(n -1, k, target - i, dp, MOD)) % MOD;
}
return dp[n][target] = ans;
}
};
classSolution {
privatestaticfinalint MOD = 1000000007;
publicintnumRollsToTarget(int n, int k, int target) {
Integer[][] dp =new Integer[n + 1][target + 1];
return helper(n, k, target, dp);
}
privateinthelper(int n, int k, int target, Integer[][] dp) {
if (target < 0) return 0;
if (n == 0) return target == 0 ? 1 : 0;
if (dp[n][target]!=null) return dp[n][target];
int ans = 0;
for (int i = 1; i <= k; i++) {
ans = (ans + helper(n - 1, k, target - i, dp)) % MOD;
}
return dp[n][target]= ans;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
classSolution {
privateval MOD = 1000000007funnumRollsToTarget(n: Int, k: Int, target: Int): Int {
val dp = Array(n + 1) { Array(target + 1) { -1 } }
funhelper(n: Int, t: Int): Int {
if (t < 0) return0if (n ==0) returnif (t ==0) 1else0if (dp[n][t] != -1) return dp[n][t]
var ans = 0for (i in1..k) {
ans = (ans + helper(n - 1, t - i)) % MOD
}
dp[n][t] = ans
return ans
}
return helper(n, target)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
classSolution:
defnumRollsToTarget(self, n: int, k: int, target: int) -> int:
MOD =10**9+7 dp = [[-1] * (target +1) for _ in range(n +1)]
defhelper(n: int, t: int) -> int:
if t <0:
return0if n ==0:
return1if t ==0else0if dp[n][t] !=-1:
return dp[n][t]
ans =0for i in range(1, k +1):
ans = (ans + helper(n -1, t - i)) % MOD
dp[n][t] = ans
return ans
return helper(n, target)
impl Solution {
pubfnnum_rolls_to_target(n: i32, k: i32, target: i32) -> i32 {
constMOD: i32=1_000_000_007;
let n = n asusize;
let target = target asusize;
let k = k asusize;
letmut dp =vec![vec![-1; target +1]; n +1];
fnhelper(n: usize, k: usize, t: usize, dp: &mut Vec<Vec<i32>>) -> i32 {
if t <0 { return0; }
if n ==0 { returnif t ==0 { 1 } else { 0 }; }
if dp[n][t] !=-1 { return dp[n][t]; }
letmut ans =0;
for i in1..=k {
if t >= i {
ans = (ans + helper(n -1, k, t - i, dp)) %MOD;
}
}
dp[n][t] = ans;
ans
}
helper(n, k, target, &mut dp)
}
}
We use dynamic programming to iteratively build the number of ways to reach each sum with a given number of dice. For each dice and each possible sum, we add up the ways to reach that sum by considering all possible face values.
classSolution {
privatestaticfinalint MOD = 1000000007;
publicintnumRollsToTarget(int n, int k, int target) {
int[][] dp =newint[n + 1][target + 1];
dp[0][0]= 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= target; j++) {
for (int face = 1; face <= k && face <= j; face++) {
dp[i][j]= (dp[i][j]+ dp[i-1][j-face]) % MOD;
}
}
}
return dp[n][target];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
classSolution {
privateval MOD = 1000000007funnumRollsToTarget(n: Int, k: Int, target: Int): Int {
val dp = Array(n + 1) { IntArray(target + 1) }
dp[0][0] = 1for (i in1..n) {
for (j in1..target) {
for (face in1..minOf(k, j)) {
dp[i][j] = (dp[i][j] + dp[i-1][j-face]) % MOD
}
}
}
return dp[n][target]
}
}
1
2
3
4
5
6
7
8
9
10
classSolution:
defnumRollsToTarget(self, n: int, k: int, target: int) -> int:
MOD =10**9+7 dp = [[0] * (target +1) for _ in range(n +1)]
dp[0][0] =1for i in range(1, n +1):
for j in range(1, target +1):
for face in range(1, min(k, j) +1):
dp[i][j] = (dp[i][j] + dp[i-1][j-face]) % MOD
return dp[n][target]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
impl Solution {
pubfnnum_rolls_to_target(n: i32, k: i32, target: i32) -> i32 {
constMOD: i32=1_000_000_007;
let n = n asusize;
let target = target asusize;
let k = k asusize;
letmut dp =vec![vec![0; target +1]; n +1];
dp[0][0] =1;
for i in1..=n {
for j in1..=target {
for face in1..=k.min(j) {
dp[i][j] = (dp[i][j] + dp[i-1][j-face]) %MOD;
}
}
}
dp[n][target]
}
}
We further optimize space by using two 1D arrays and prefix sums, keeping only the current and previous states. This reduces space usage from O(n * target) to O(target).