Dice Roll Simulation

hard dynamic programming counting

Problem

A die is rolled n times. The array rollMax has length 6, where rollMax[k] is the maximum number of times the face value (k + 1) may appear consecutively. Return the number of distinct sequences of length n that obey every consecutive limit, modulo 109 + 7.

Inputn = 2, rollMax = [1, 1, 2, 2, 2, 3]
Output34
There are 6 × 6 = 36 sequences of length 2; the pairs (1,1) and (2,2) are forbidden because faces 1 and 2 may repeat at most once, leaving 34.

def dieSimulator(n, rollMax):
    MOD = 10**9 + 7
    # dp[f][c] = sequences ending in face f with c consecutive f's
    dp = [[0] * (rollMax[f] + 1) for f in range(6)]
    for f in range(6):
        dp[f][1] = 1
    for _ in range(n - 1):
        nxt = [[0] * (rollMax[f] + 1) for f in range(6)]
        for f in range(6):
            total = sum(dp[g][c] for g in range(6) for c in range(1, rollMax[g] + 1))
            same = sum(dp[f][c] for c in range(1, rollMax[f] + 1))
            for c in range(1, rollMax[f] + 1):
                if c == 1:
                    nxt[f][1] = (total - same) % MOD
                else:
                    nxt[f][c] = dp[f][c - 1]
        dp = nxt
    return sum(dp[f][c] for f in range(6) for c in range(1, rollMax[f] + 1)) % MOD
function dieSimulator(n, rollMax) {
  const MOD = 1000000007n;
  let dp = rollMax.map(m => new Array(m + 1).fill(0n));
  for (let f = 0; f < 6; f++) dp[f][1] = 1n;
  for (let r = 1; r < n; r++) {
    const nxt = rollMax.map(m => new Array(m + 1).fill(0n));
    let total = 0n;
    for (let g = 0; g < 6; g++)
      for (let c = 1; c <= rollMax[g]; c++) total += dp[g][c];
    for (let f = 0; f < 6; f++) {
      let same = 0n;
      for (let c = 1; c <= rollMax[f]; c++) same += dp[f][c];
      for (let c = 1; c <= rollMax[f]; c++)
        nxt[f][c] = c === 1 ? ((total - same) % MOD + MOD) % MOD : dp[f][c - 1];
    }
    dp = nxt;
  }
  let ans = 0n;
  for (let f = 0; f < 6; f++)
    for (let c = 1; c <= rollMax[f]; c++) ans = (ans + dp[f][c]) % MOD;
  return Number(ans);
}
class Solution {
    public int dieSimulator(int n, int[] rollMax) {
        final long MOD = 1_000_000_007L;
        long[][] dp = new long[6][];
        for (int f = 0; f < 6; f++) { dp[f] = new long[rollMax[f] + 1]; dp[f][1] = 1; }
        for (int r = 1; r < n; r++) {
            long[][] nxt = new long[6][];
            long total = 0;
            for (int g = 0; g < 6; g++)
                for (int c = 1; c <= rollMax[g]; c++) total += dp[g][c];
            total %= MOD;
            for (int f = 0; f < 6; f++) {
                nxt[f] = new long[rollMax[f] + 1];
                long same = 0;
                for (int c = 1; c <= rollMax[f]; c++) same += dp[f][c];
                for (int c = 1; c <= rollMax[f]; c++)
                    nxt[f][c] = c == 1 ? ((total - same) % MOD + MOD) % MOD : dp[f][c - 1];
            }
            dp = nxt;
        }
        long ans = 0;
        for (int f = 0; f < 6; f++)
            for (int c = 1; c <= rollMax[f]; c++) ans = (ans + dp[f][c]) % MOD;
        return (int) ans;
    }
}
int dieSimulator(int n, vector<int>& rollMax) {
    const long long MOD = 1000000007LL;
    vector<vector<long long>> dp(6);
    for (int f = 0; f < 6; f++) { dp[f].assign(rollMax[f] + 1, 0); dp[f][1] = 1; }
    for (int r = 1; r < n; r++) {
        vector<vector<long long>> nxt(6);
        long long total = 0;
        for (int g = 0; g < 6; g++)
            for (int c = 1; c <= rollMax[g]; c++) total += dp[g][c];
        total %= MOD;
        for (int f = 0; f < 6; f++) {
            nxt[f].assign(rollMax[f] + 1, 0);
            long long same = 0;
            for (int c = 1; c <= rollMax[f]; c++) same += dp[f][c];
            for (int c = 1; c <= rollMax[f]; c++)
                nxt[f][c] = c == 1 ? ((total - same) % MOD + MOD) % MOD : dp[f][c - 1];
        }
        dp = nxt;
    }
    long long ans = 0;
    for (int f = 0; f < 6; f++)
        for (int c = 1; c <= rollMax[f]; c++) ans = (ans + dp[f][c]) % MOD;
    return (int) ans;
}
Time: O(n · 6 · max(rollMax)) Space: O(6 · max(rollMax))