1. 题目与解析
有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数。
不过我们在使用它时有个约束,就是使得投掷骰子时,连续 掷出数字 i 的次数不能超过 rollMax[i](i 从 1 开始编号)。
现在,给你一个整数数组 rollMax 和一个整数 n,请你来计算掷 n 次骰子可得到的不同点数序列的数量。
假如两个序列中至少存在一个元素不同,就认为这两个序列是不同的。由于答案可能很大,所以请返回 模 10^9 + 7 之后的结果。
输入: n = 2, rollMax = [1,1,2,2,2,3]
输出: 34
解释: 我们掷 2 次骰子,如果没有约束的话,共有 6 * 6 = 36 种可能的组合。但是根据 rollMax 数组,数字 1 和 2 最多连续出现一次,所以不会出现序列 (1,1) 和 (2,2)。因此,最终答案是 36-2 = 34。
输入: n = 2, rollMax = [1,1,1,1,1,1]
输出: 30
输入: n = 3, rollMax = [1,1,1,2,2,3]
输出: 181
本题可以使用动态规划的方式进行求解,因此,需要重点考虑的,就是确定其状态转移方程。
可以确定的是,一定需要的两个维度是n位数字以及在每一位上可能存在的6种情况dp[n][6];但是,对于本题目而言,这是不够的,因为我们需要考虑同一数字连续出现的次数不能超过某个阈值,根据题意,这个阈值的大小肯定不会超过16,因此我们开辟dp[n][6][16]的空间就可以容纳所有的状态。
2. 题解
class Solution {
static final int MOD = 1000000007;
public int dieSimulator(int n, int[] rollMax) {
int[][][] d = new int[n + 1][6][16];
for (int j = 0; j < 6; j++) {
d[1][j][1] = 1;
}
for (int i = 2; i <= n; i++) {
for (int j = 0; j < 6; j++) {
for (int k = 1; k <= rollMax[j]; k++) {
for (int p = 0; p < 6; p++) {
if (p != j) {
d[i][p][1] = (d[i][p][1] + d[i - 1][j][k]) % MOD;
} else if (k + 1 <= rollMax[j]) {
d[i][p][k + 1] = (d[i][p][k + 1] + d[i - 1][j][k]) % MOD;
}
}
}
}
}
int res = 0;
for (int j = 0; j < 6; j++) {
for (int k = 1; k <= rollMax[j]; k++) {
res = (res + d[n][j][k]) % MOD;
}
}
return res;
}
}