Digit DP

O(digits · states · 10)

Count numbers in [0, N] with some digit property by building N digit by digit. The two universal state flags: tight (are we still glued to N's prefix, so the next digit is capped?) and started (have we placed a nonzero digit yet, so leading zeros don't pollute the property?). Answer queries on [a, b] as solve(b) - solve(a-1). The property itself rides along as extra state; here it is the previous digit.

// use it on

CSES: Counting Numbers

Count numbers in [a,b] with no two adjacent equal digits. Exactly this template; a can be 0, so handle solve(-1) = 0 rather than subtracting blindly.

// the code

// count x in [0, n] with no two equal adjacent digits
long long solve(long long n) {
    if (n < 0) return 0;
    string s = to_string(n);
    int L = s.size();
    // memo[pos][prev] for the free (not tight, started) states only
    vector<vector<long long>> memo(L, vector<long long>(11, -1));
    auto rec = [&](auto&& self, int pos, int prev, bool tight, bool started) -> long long {
        if (pos == L) return 1;
        if (!tight && memo[pos][prev + 1] != -1 && started)
            return memo[pos][prev + 1];
        long long res = 0;
        int hi = tight ? s[pos] - '0' : 9;
        for (int d = 0; d <= hi; d++) {
            if (started && d == prev) continue;
            res += self(self, pos + 1, (started || d) ? d : -1,
                        tight && d == hi, started || d);
        }
        if (!tight && started) memo[pos][prev + 1] = res;
        return res;
    };
    return rec(rec, 0, -1, true, false);
}
// answer for [a, b]: solve(b) - solve(a - 1)

// more digits & optimization