1、动态规划法
我们可以利用数组 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]来表示当我们已经投过 i i i次骰子,其中第 i i i次投出的骰子是 j j j,此时连续投出骰子 j j j的次数为 k k k。因此我们可以根据上一轮中得到的状态 d p [ i − 1 ] [ j ] [ k ] dp[i-1][j][k] dp[i−1][j][k],结合本次投骰子获得的结果 p p p得到如下的转移关系:
1、若
p
≠
j
p \ne j
p=j,则此时我们不需要考虑上一次投骰子对于本次结果的影响,故
d
[
i
]
[
p
]
[
1
]
=
(
d
[
i
]
[
p
]
[
1
]
+
d
[
i
−
1
]
[
j
]
[
k
]
)
%
m
o
d
d[i][p][1] = (d[i][p][1] + d[i - 1][j][k]) \% mod
d[i][p][1]=(d[i][p][1]+d[i−1][j][k])%mod;
2、若
p
=
j
p=j
p=j,则此时我们需要对上一次投出
p
p
p时的次数进行讨论,若
k
+
1
≤
r
o
l
l
M
a
x
[
j
]
k + 1 \le rollMax[j]
k+1≤rollMax[j]则说明此时我们连续投出的次数未超过上限,可以继续累加,即
d
[
i
]
[
p
]
[
k
+
1
]
=
(
d
[
i
]
[
p
]
[
k
+
1
]
+
d
[
i
−
1
]
[
j
]
[
k
]
)
%
m
o
d
d[i][p][k + 1] = (d[i][p][k + 1] + d[i - 1][j][k]) \% mod
d[i][p][k+1]=(d[i][p][k+1]+d[i−1][j][k])%mod,否则说明此时超出上限,赋默认值为0即可。
最终,我们只需要在遍历一遍数组,累加求和 ∑ j = 0 5 ∑ k = 1 r o l l M a x [ j ] d p [ n ] [ j ] [ k ] \sum_{j=0}^{5}\sum_{k=1}^{rollMax[j]}dp[n][j][k] ∑j=05∑k=1rollMax[j]dp[n][j][k]即可。
class Solution {
public:
static constexpr int mod = 1E9 + 7;
int dieSimulator(int n, vector<int>& rollMax) {
vector d(n + 1, vector(6, vector<int>(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;
}
};
2、动态规划法优化
我们可以定义状态
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示已经完成
i
i
i次投骰子,其中第
i
i
i次投出是
j
j
j的合法序列数,显然我们可以得到状态转移公式如下:
d
p
[
i
]
[
j
]
=
∑
t
=
1
r
o
l
l
M
a
x
[
j
]
∑
k
=
0
k
≠
j
5
d
[
i
−
t
]
[
k
]
dp[i][j]=\sum_{t=1}^{rollMax[j]}\sum_{\begin{matrix} k=0\\k\ne j\end{matrix}}^{5} d[i-t][k]
dp[i][j]=t=1∑rollMax[j]k=0k=j∑5d[i−t][k],表示当我们需要求
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]时,可以从上一次不为
j
j
j的位置开始累加。
基于上式,我们可以发现
d
p
[
i
−
1
]
[
j
]
dp[i−1][j]
dp[i−1][j]和
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]存在大量相同项,可以表示为:
d
p
[
i
]
[
j
]
=
∑
k
=
0
5
d
p
[
i
−
1
]
[
k
]
−
∑
k
=
0
k
≠
j
5
d
p
[
i
−
r
o
l
l
M
a
x
[
j
]
−
1
]
[
k
]
dp[i][j]=\sum_{k=0}^{5}dp[i-1][k]-\sum_{\begin{matrix}k=0\\k\ne j\end{matrix}}^{5}dp[i-rollMax[j]-1][k]
dp[i][j]=k=0∑5dp[i−1][k]−k=0k=j∑5dp[i−rollMax[j]−1][k]
class Solution {
public:
static constexpr int mod = 1E9 + 7;
int dieSimulator(int n, vector<int>& rollMax) {
vector d(n + 1, vector<int>(6, 0));
vector<int> sum(n + 1, 0);
sum[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 6; j++) {
int pos = max(i - rollMax[j] - 1, 0);
int sub = ((sum[pos] - d[pos][j]) % mod + mod) % mod;
d[i][j] = ((sum[i - 1] - sub) % mod + mod) % mod;
if (i <= rollMax[j]) {
d[i][j] = (d[i][j] + 1) % mod;
}
sum[i] = (sum[i] + d[i][j]) % mod;
}
}
return sum[n];
}
};