Digital DP algorithm learning summary

1. Brief description of digital dp + template

Digital dp is a dynamic programming algorithm used for counting. Generally, it is necessary to count the number of numbers that meet the given conditions in an interval [left, right] . For example, HDU 2089 does not include 4 and 62 in the given interval The number of 62 numbers, the number of digits dp is actually the optimization of the violent enumeration algorithm, by filtering some numbers, and memorizing (to be discussed below) some data, to optimize the time complexity.

First, the dfs ( int step , int state , bool lead , bool limit ) function has four parameters

  • step: Indicates the number of digits currently enumerated, such as 1-100, first enumerates the hundreds-digit number, then enumerates the tens-digit number, and finally enumerates the single-digit number

  • state: state condition, used for memorization, for example, if we want to count the number of numbers between [1,9299] that do not contain 4, it stands to reason that we should start enumerating from 1 first, when the enumeration reaches 1000, then We already know that when there are only three digits, the number of digits without 4 is not included, then when we are enumerating the number of thousands, when the digit of thousands is 1, we already know that the following three digits are not For the number of numbers containing 4, when the thousands digit comes to 2, we can return the result directly, because the thousands digit 1 and 2 do not contain 4, then the three digits after the thousands digit 1 and the thousands digit 2 will not matter How to match, the number without the number 4 must be the same, so that the array can be memorized to avoid repeated calculations.

  • lead: Leading zeros, leading zeros such as 00xxx in some problems will also affect the results, so a bool variable lead must be set. Of course, in some problems, leading zeros will not affect the results, so you can not use it

  • limit: limit mark, we want to enumerate all numbers, these numbers must have an upper bound, for example, above we want to enumerate the data between [1,9299], when the thousands digit is 9, obviously the hundreds digit is the highest It can only be enumerated to 2, otherwise it exceeds the upper bound of the enumeration, but when the thousands digit is 8, there is no upper bound at this time, because the thousands digit is 8, no matter what the next three digits are Will not exceed the range of 9299

Secondly, the function of solve ( int x ) is to take out each digit of a number for traversal of dfs

The following is a template for digital dp:

#include<iostream>
using namespace std;
int a[20]; //存储数字位数
int dp[20][2]; //记忆化数组

int dfs(int step, int state, bool lead, bool limit) {
    if (step == -1) return 1; //当遍历到超出数字位数时,说明此情况可行,返回1
    if (!limit && !lead && dp[step][state] != -1) //记忆化,节省重复计算
        return dp[step][state];
    int up = limit ? v[step] : 9;  //取得上界
    int ans = 0; //开始计数
    for (int i = 0; i <= up; i++) {
        if (条件1) ...
        if (条件2) ...
        ans += dfs(step - 1, /*状态转移*/, lead && i == 0, limit && i == v[step]);
    }
    if (!limit && !lead) //在一定条件下记录结果,对应上面记忆化
        dp[step][state] = ans;
    return ans;
}
int solve(int x) {
    int pos = 0;
    while (x) { //取出各个位的数字,存在a中
        a[pos++] = x % 10;
        x /= 10;
    }
    memset(dp, -1, sizeof(dp)); //初始化dp数组值为-1
    return dfs(pos - 1, /*状态*/, true, true); //刚开始比最高位还高的数字为0,所以有前导零,并且有限制
}
int main() {
    int le, ri;
    while (cin >> le >> ri) {
        int ans = solve(ri) - solve(le - 1);
        cout << ans << endl;
    }
    return 0;
}

2. HDU 2089 does not need 62 -digit dp solution

The state variable should be memorized with the most restrictive condition. For example, there is no 62 limit in this question, and there is no limit of 4. There is only one bit, so the state is marked as whether the bit is 6. Assume that the solution in [1,100] meets the conditions The number, if the state is expressed as is_four, then the tens digit is 5 and the tens digit is 6, and the digits that meet the conditions are the same, because neither 5 nor 6 is 4, but when the tens digit is 6, the ones digit It cannot be 2 (this is required by the title), so the data inconsistency is caused, and it is concluded that the state variable should be memorized with the most restrictive conditions.

#include<iostream>
#include<vector>
using namespace std;
int a[20];
int dp[20][2];

int dfs(int step, int pre, bool is_six, bool limit) { 
    //pre为前一位数字,用于判断是否存在62,此处is_six就是模板中的state,表示当此位为6和不为6时,后续的结果不同
    if (step == -1) return 1;
    if (!limit && dp[step][is_six] != -1) 
        return dp[step][is_six];
    int up = limit ? a[step] : 9;
    int ans = 0;
    for (int i = 0; i <= up; i++){
        if (i == 4) continue; //存在4则跳过
        if (i == 2 && pre == 6) continue; //存在62则跳过
        ans += dfs(step - 1, i, i == 6, limit && i == a[step]);
    }
    if (!limit) 
        dp[step][is_six] = ans;
    return ans;
}
int solve(int x) {
    int pos = 0;
    while (x != 0) {
        a[pos++] = x % 10;
        x /= 10;
    }
    memset(dp, -1, sizeof(dp)); //初始化dp数组值为-1
    return dfs(pos - 1, -1, 0, true);
}
int main() {
    int n, m;
    while (cin >> n >> m && n != 0 && m != 0) {
        int ans = solve(m) - solve(n - 1);
        cout << ans << endl;
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_21891843/article/details/129767659