NeFut Logo NeFut
Admin Login

Digit Dynamic Programming: In-Depth Analysis of Efficient Counting and State Management

Published at: 2026-05-27 09:17 Last updated: 2026-06-06 13:04
#C++ #Tutorial

Core Logic and Mathematical Principles

The essence of Digit Dynamic Programming (Digit DP) is to reduce the macro comparison of numerical sizes into a dimensional mapping represented as a "string-like" topological state transition of digits from high to low in a specific base.

Digit DP is specifically designed to solve counting problems of the type "how many integers in the interval $[L, R]$ satisfy a certain specific digit characteristic (e.g., not containing 49, the difference between adjacent digits $ ge 2$, the sum of digits being prime, etc.)". Its core idea lies in utilizing prefix sums, memoized search, and upper limit constraints controlling high digits over low digits.

1. Geometric Splitting of Space: Prefix Sum Differentiation

Directly finding the numbers that meet the conditions in the interval $[L, R]$ often faces complex bilateral boundary constraints. Digit DP strictly adheres to the prefix sum differentiation principle, transforming any interval query into an independent unidirectional query starting from 0:

$$ \text{Ans}(L, R) = \text{Ans}(0, R) - \text{Ans}(0, L - 1) $$

This allows us to focus solely on solving the core proposition of "how many numbers in $[0, N]$ satisfy the conditions".

2. Topological Decoupling of Numerical Upper Limits: limit Marker Principle

Assuming $N = 3125$. When we start filling digits from the highest place (thousands place) to the lower places:

This dynamic constraint caused by the choice of high digits over the range of options for low digits is referred to in Digit DP as the limit constraint:


State Design and Memoized Search Network

The most standard and error-free implementation scheme of Digit DP in competitive programming is memoized search based on DFS.

1. Standard Control Skeleton of DFS State Space

A standard Digit DP search function usually includes the following core control parameters: int dfs(int pos, int state, bool lead, bool limit)

2. Core Conditions for State Memoization

The prerequisite for the memoization array f[pos][state] in Digit DP to be reusable is: the current search branch must be in the state of limit = false and lead = false.

Physical Reason: If limit = true, it indicates that the current count of numbers obtained is subject to the local constraint of $N$, and it is not a complete set, thus cannot be written into the global memoization array. Only when the upper limit is fully released and leading zeros are completely detached can the solutions found in lower places be universal enough to be solidified into the f array.


C++ Standard Source Code (NOIP/Comprehensive Template for Improvement Group)

The following code solves the classic introductory problem of Digit DP: "count the number of integers in the interval $[L, R]$ that do not contain the digit 4 and do not contain consecutive digits 62" (Luogu P2602 / Classic Wind Flow Digit DP Model), strictly compatible with the Linux g++ -O2 environment.

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

int digits[20]; // Decomposed storage of the digits of number N
int f[20][10];  // f[pos][pre_digit] memoized state grid

// pos: current place; pre: the digit filled in the previous place; lead: whether there are leading zeros; limit: whether there is a highest place limit
int dfs(int pos, int pre, bool lead, bool limit) {
    // Termination condition: all digit decisions are completed, successfully forming a valid number, return 1
    if (pos < 0) return 1;

    // Memoization trigger: only in a "free state" without any restrictions and without leading zeros can the old cache be referenced
    if (!limit && !lead && f[pos][pre] != -1) {
        return f[pos][pre];
    }

    // Dynamically calculate the upper limit of the current digit enumeration
    int up = limit ? digits[pos] : 9;
    int res = 0;

    for (int i = 0; i <= up; ++i) {
        // Pruning interception: cannot contain 4
        if (i == 4) continue;
        // Pruning interception: cannot contain consecutive 62
        if (pre == 6 && i == 2) continue;

        // Recursive control transmission:
        // 1. New leading zero state: if current is a leading zero and the current place is filled with 0, the next place is still a leading zero
        // 2. New highest place limit: if current is limited and the current place has filled the theoretical upper limit digit, the next place will have the highest place limit
        res += dfs(pos - 1, i, lead && (i == 0), limit && (i == up));
    }

    // Solidifying state cache: only the free state can be recorded
    if (!limit && !lead) {
        f[pos][pre] = res;
    }

    return res;
}

// Solve the total number of valid numbers in [0, n]
int solve(int n) {
    if (n < 0) return 0;
    if (n == 0) return 1; // 0 itself is a valid number (does not contain 4, does not contain 62)

    int len = 0;
    // Decompose the decimal number from low to high into the array
    while (n > 0) {
        digits[len++] = n % 10;
        n /= 10;
    }

    // Start recursion: begin from the highest valid place (len - 1), assign the previous place a safe sentinel value of 0, initially in the highest place limit and leading zero state
    return dfs(len - 1, 0, true, true);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    memset(f, -1, sizeof(f)); // The global state grid only needs to be initialized once

    int l, r;
    while (cin >> l >> r && (l || r)) {
        // Utilize prefix sum differentiation to capture interval answers without loss
        cout << solve(r) - solve(l - 1) << "\n";
    }

    return 0;
}

NOIP Practical Avoidance Guide

1. Misinitialization of Memoization Array in solve Function

2. Ignoring Boundary Underflow of solve(L - 1) When $L=0$


Classic NOIP/Luogu Real Problems

1. Luogu P2602 [ZJOI2010] Digit Counting

2. Luogu P4999 Annoying Math Homework

Original Source: local://18.1

[h] Back to Home