Skip to content

數位 DP (位數 DP)

有多少數字滿足題目條件。

常見的狀態維度為 (1) 前 位數 (2) 最後一位放的數字 (3) 前 位數是否和 的前 位一致。

題目變形,詢問 之間有多少數字滿足題目條件:分別做 的結果再相減。

AtCoder Beginner Contest 154E – Almost Everywhere Zero

中有幾個數字包含 個非 數字。

  • 狀態: 代表前 位數,有 個非 數字, 代表前 位剛好是 的前 位的狀況, 則為至少一位數小於 N 的相對位數的狀況,。
  • 初始狀態:
  • 轉移:假設現在要填入
    • 如果 ,否則不變。
    • 如果 是非法的。

第三個狀態用來判斷第 位數的合法範圍:

  • 假設
    • 如果前 位數字為 ,第 位數可以是
    • 如果前 位數字為 ,第 位數可以是
  • 現在要填入第 位,
    • 如果前 位數字和 的前 位數字相同,第 位數可以是
    • 如果前 位數字和 的前 位數字不同,第 位數可以是
參考程式碼
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#define FOR(i, L, R) for (int i = L; i != (int)R; ++i)
int dp[105][4][2];

int main()
{
    string s;
    int n, K;
    cin >> s >> K;
    n = (int)s.size();
    dp[0][0][0] = 1;
    FOR(i, 0, n) FOR(j, 0, 4) FOR(k, 0, 2)
    {
        int nd = (s[i] - '0');
        FOR(d, 0, 10)
        {
            int ni = i + 1, nj = j, nk = k;
            if (d != 0)
                ++nj;
            if (nj > K)
                continue;
            if(k == 0)
            {
                if(d > nd)
                    continue;
                if(d < nd)
                    nk = 1;
            }
            dp[ni][nj][nk] += dp[i][j][k];
        }
    }
    int ans = dp[n][K][0] + dp[n][K][1];
    cout << ans << '\n';
}
AtCoder Educational DP Contest S

問從 中,用十位數表示,位數和是 的倍數得有多少數字。

  • 狀態: 位數數字,對 取餘數結果為 ,前 位數和 的前 位數 ( 不同, 相同),有幾個數字
  • 轉移:假設現在要填入
    • 如果 是非法的。