数位dp专题

本质上就是动态规划,只需记录位数和前一个数的状态,其后满足条件的个数是固定的
数位dp还要多记录一个受限状态,以及前面全为0的特殊处理状态

处理范围内的数时,相当于利用前缀和的思想进行处理
我们可以用f(n)表示[0,n]的所有满足条件的个数,我们对于[l,r] 区间内满足条件的个数,就可以用[l,r] ⟺ f (r)−f(l−1)

数位dp模板

auto s = to_string(n); //转字符串逐位递归分析
int m = s.length(), memo[m][10];
memset(memo,-1,sizeof(memo));
function<int(int, int, bool)> f = [&](int i,int mask, bool is_limit,bool is_num) -> int {//视情况记录已遍历值的某种特征,如1的个数,mask状态,
    if (i == m) 
        return is_num;//边界直接返回前面累积的1
    if (!is_limit&&is_nummemo[i][mask]!= -1) //已经存储过,直接剪枝返回,核心语句,记忆化搜索
        return memo[i][mask];
    int res = 0; //计算1出现的个数
    if(!is_num) res = f(i + 1, mask, false, false);//处理特殊情况

    int up = is_limit ? s[i] - '0' : 9; // 根据受限与否决定枚举数上界
    int down = is_num? 0: 1;//根据特殊情况与否决定下界
    //做选择
    for (int d = down; d <= up; ++d) 
            res += f(i + 1, d, is_limit && d == up,true);//移动到下一位

    if (!is_limit&&is_num) //记录非限制数
        memo[i][mask] = res;
    return res;
};
return f(0,0,true,false);   //从下标0开始,刚开始受限

1. 统计整数数目

2. 至少有一位重复的数字

3. 数字1的个数

4. 不含连续1的非负整数

5. 最大为N的数字组合

6. 找到所有好字符串

7. 统计范围内的步进数字数目

8. 范围中美丽整数的数目

posted @ 2023-06-04 17:59  失控D大白兔  阅读(16)  评论(0编辑  收藏  举报