3129. Find All Possible Stable Binary Arrays I

練習日期:2026-03-09

難度:Medium

類型:Dynamic Programming、Prefix Sum

📘 題目敘述

給你三個正整數 zeroonelimit

如果一個二元陣列 arr 滿足以下條件,就稱它是 stable:

  • arr0 出現的次數恰好是 zero
  • arr1 出現的次數恰好是 one
  • arr 中每一個長度大於 limit 的子陣列,都必須同時包含 01

請回傳 stable binary arrays 的總數。

由於答案可能非常大,請將結果對 10^9 + 7 取模後回傳。

條件限制

  • 1 <= zero, one, limit <= 200

🧠 解題思路

這題的重點不是只看目前放了幾個 0 跟幾個 1,還要知道:

  • 最後一個數字是什麼
  • 最後連續出現了幾個一樣的數字

因為題目限制的是:不能出現長度超過 limit 的全 0 或全 1 子陣列。換句話說,就是 同一個數字最多只能連續出現 limit

所以這題很適合用 DP 紀錄狀態。

我這份程式的做法是:

  • z 表示目前已經用了幾個 0
  • o 表示目前已經用了幾個 1
  • b 表示目前最後一個數字是 0 還是 1
  • l 表示目前尾端連續幾個 b

只要知道這四個資訊,就能決定下一步可不可以再放同樣的數字,或是改放另一種數字。

也就是說,這題的核心就是:

dp[z][o][b][l] 表示:目前已經用了 z0o1,最後一個數字是 b,而且尾端連續有 lb 的 stable array 數量。

接下來就從這個狀態去轉移:

  • 如果最後是 0
    • 還可以再放 0,前提是 z < zerol < limit
    • 也可以改放 1,前提是 o < one
  • 如果最後是 1
    • 還可以再放 1,前提是 o < onel < limit
    • 也可以改放 0,前提是 z < zero

最後把所有剛好用完 zero0one1 的合法狀態加總起來,就是答案。

所有變數

  • dp[201][201][2][201]:DP 陣列,dp[z][o][b][l] 表示目前已用 z0o1,最後數字是 b,尾端連續長度是 l 的合法陣列數量
  • MOD:模數 1000000007
  • z:目前 DP 狀態中已經使用的 0 的數量
  • o:目前 DP 狀態中已經使用的 1 的數量
  • b:目前最後一個數字,0 代表最後是 01 代表最後是 1
  • l:目前尾端連續相同數字的長度
  • now:目前這個 DP 狀態的方案數
  • ans:最後答案
  • k:最後加總答案時,枚舉尾端連續長度用的變數

🪜 主要流程步驟

1. 定義 DP 狀態

先開一個四維 DP:

dp[z][o][b][l]

它代表:

  • 已經用了 z0
  • 已經用了 o1
  • 最後一個數字是 b
  • 最後連續有 lb

這樣的設計很重要,因為題目限制跟「尾端連續長度」直接有關,所以不能只記錄用了幾個 01


2. 初始化長度為 1 的情況

一開始可以先放一個 0,或者先放一個 1

dp[1][0][0][1] = 1;
dp[0][1][1][1] = 1;

意思是:

  • 用 1 個 0、0 個 1,最後是 0,而且尾端連續 1 個 0,有 1 種
  • 用 0 個 0、1 個 1,最後是 1,而且尾端連續 1 個 1,有 1 種

這就是整個 DP 的起點。


3. 枚舉所有可能的狀態

接著用四層迴圈枚舉所有可能的 DP 狀態:

  • z:從 0zero
  • o:從 0one
  • b01
  • l:從 1limit

每次先取出目前這格的方案數:

int now = dp[z][o][b][l];

如果這格是 0,代表目前沒有任何合法方法走到這個狀態,就直接跳過:

if (now == 0) {
    continue;
}

4. 如果最後一個數字是 0,就考慮接下來放什麼

b == 0 時,代表目前陣列最後是 0

這時有兩種選擇。

第一種是再放一個 0

if (z < zero && l < limit) {
    dp[z + 1][o][0][l + 1] += now;
    dp[z + 1][o][0][l + 1] %= MOD;
}

這段表示:

  • 還有 0 可以用,也就是 z < zero
  • 而且目前尾端連續 0 的長度還沒到上限,也就是 l < limit

那就可以再接一個 0,所以:

  • z + 1
  • o 不變
  • 最後仍然是 0
  • 尾端連續長度從 l 變成 l + 1

第二種是改放一個 1

if (o < one) {
    dp[z][o + 1][1][1] += now;
    dp[z][o + 1][1][1] %= MOD;
}

這時因為尾端數字從 0 換成 1,所以新的連續長度要重設成 1


5. 如果最後一個數字是 1,就考慮接下來放什麼

b == 1 時,邏輯完全對稱。

如果還能再放 1,而且連續長度還沒超過 limit

if (o < one && l < limit) {
    dp[z][o + 1][1][l + 1] += now;
    dp[z][o + 1][1][l + 1] %= MOD;
}

這表示:

  • 再補一個 1
  • o 增加
  • 最後仍然是 1
  • 尾端連續長度變成 l + 1

如果要改放 0

if (z < zero) {
    dp[z + 1][o][0][1] += now;
    dp[z + 1][o][0][1] %= MOD;
}

這時最後數字變成 0,所以尾端連續長度重新變成 1


6. 為什麼這樣就能保證 stable

題目說,任何長度大於 limit 的子陣列都必須同時包含 01

這句其實等價於:

  • 不能有連續超過 limit0
  • 不能有連續超過 limit1

而這份程式正是靠 l < limit 這個條件,保證不會把同樣的數字接到超過上限。

所以只要這個 DP 狀態合法,往後的轉移也都合法。


7. 最後把所有剛好用完 zero 和 one 的狀態加總

最後答案不是只看某一個固定 l,因為尾端連續長度可能是 12、...、limit

所以要把:

  • dp[zero][one][0][k]
  • dp[zero][one][1][k]

全部加起來:

for (int k = 1; k <= limit; k++) {
    ans = (ans + dp[zero][one][0][k]) % MOD;
    ans = (ans + dp[zero][one][1][k]) % MOD;
}

這樣就把所有:

  • 用完 zero0
  • 用完 one1
  • 最後可能是 01
  • 尾端連續長度任意合法值

的 stable arrays 全部統計進去了。

⏱️ 複雜度

  • 時間複雜度:O(zero * one * limit)
    四維狀態中,b 只有 2 種,所以可視為常數。
  • 空間複雜度:O(zero * one * limit)
    需要一個四維 DP 陣列來記錄狀態。

💻 程式碼實作

class Solution {
public:
    int numberOfStableArrays(int zero, int one, int limit) {
        static int dp[201][201][2][201]; // 已用0、已用1、最後數字、最後長度
        memset(dp, 0, sizeof(dp));
        dp[1][0][0][1] = 1;
        dp[0][1][1][1] = 1;
        const int MOD = 1000000007;
        for (int z = 0; z <= zero; z++) {
            for (int o = 0; o <= one; o++) {
                for (int b = 0; b < 2; b++) {
                    for (int l = 1; l <= limit; l++) {
                        int now = dp[z][o][b][l];
                        if (now == 0) {
                            continue;
                        }
                        if (b == 0) {
                            if (z < zero && l < limit) { // 再放0
                                dp[z + 1][o][0][l + 1] += now;
                                dp[z + 1][o][0][l + 1] %= MOD;
                            }
                            if (o < one) { // 再放1
                                dp[z][o + 1][1][1] += now;
                                dp[z][o + 1][1][1] %= MOD;
                            }
                        } else {
                            if (o < one && l < limit) { // 再放0
                                dp[z][o + 1][1][l + 1] += now;
                                dp[z][o + 1][1][l + 1] %= MOD;
                            }
                            if (z < zero) { // 再放1
                                dp[z + 1][o][0][1] += now;
                                dp[z + 1][o][0][1] %= MOD;
                            }
                        }
                    }
                }
            }
        }
        int ans = 0;
        for (int k = 1; k <= limit; k++) {
            ans = (ans + dp[zero][one][0][k]) % MOD;
            ans = (ans + dp[zero][one][1][k]) % MOD;
        }
        return ans;
    }
};

https://leetcode.com/problems/find-all-possible-stable-binary-arrays-i/

作者: scottnick
撰寫日期: 2026-03-09
類別:
原文連結: https://scottnick.github.io/cpp-notes/all%20problems/3129-find-all-possible-stable-binary-arrays-i.html