快捷键

切换暗色模式 CtrlD
搜索 CtrlK
关闭弹窗 Esc
返回顶部 Ctrl
快捷键面板 Ctrl/
C++信息学奥赛打字闯关
首页 闯关训练 段位系统 题库中心
技术博客 新闻资讯
排行榜 信奥社区 成就殿堂 在线留言 AI助手
📑 文章目录

数位 DP 从入门到精通:模板与经典例题详解

❤️ 660 点赞
💬 0 评论
👁️ 21010 阅读
🔄 更新于 2026-09-11 05:13

数位 DP 是处理"范围内满足某条件的数的个数"这类问题的标准方法。

一、什么是数位 DP?
按数位(个位、十位、百位...)逐位进行 DP,通常解决这类问题:

  • 求 [L, R] 内满足某种性质的数的个数

  • 求 [L, R] 内不含某些数字的数的个数


二、核心模板
int dp[20][state]; // pos: 当前位, state: 状态
int dfs(int pos, int state, bool limit, bool lead) {
    if (pos == 0) return check(state);
    if (!limit && !lead && dp[pos][state] != -1) return dp[pos][state];
    int up = limit ? num[pos] : 9;
    int ans = 0;
    for (int i = 0; i <= up; i++) {
        ans += dfs(pos-1, next_state(state, i), limit && i==up, lead && i==0);
    }
    if (!limit && !lead) dp[pos][state] = ans;
    return ans;
}


三、核心参数解释
  • pos:当前处理的位数(从高位到低位)

  • state:当前状态(根据题目设计)

  • limit:是否卡上限(前面对应位置都等于上限数字)

  • lead:是否有前导零


四、常见状态设计
  • 最简单的:是否需要记录已经出现过哪些数字

  • 模运算:记录当前数 mod 某个值的余数

  • 差分:用前缀和思想,solve(R) - solve(L-1)


五、经典例题
  1. 洛谷 P2657 windy 数(相邻数字差 >= 2)

  2. 洛谷 P2602 数字计数(统计每个数字出现次数)

  3. 洛谷 P4124 手机号码(包含特定数字组合)

  4. 洛谷 P4999 烦人的数学作业


六、进阶技巧
  • 记忆化只在不卡上限、无前导零时记录

  • 状态压缩存储"已出现过哪些数字"

  • 同时处理多个约束

💬 评论 (0)

暂无评论,快来抢沙发吧~ 🛋️

在线

给管理员留言

每条留言老师都会认真阅读并回复

📚 课程咨询 🔧 技术求助 💡 建议反馈 🤝 合作联系

留言发送成功!

您的留言已送达管理员后台

追踪码(请保存以便查询回复)
------