数位 dp 总结

用途:统计 \([1,x]\) 中满足某某性质的数的个数。

(当然,如果题目要求统计 \([l,r]\) 中的数,那么用 \([1,r]\) 的答案减 \([1,l-1]\) 的答案即可)

数据范围:\(10^9\) 起步。

状态:现在是第几位(\(x\),并记这一位上的数字为 \(num_x\))、有没有前导零(\(zer\))、能枚举的范围是 \([0,9]\) 还是 \([0,num_x]\)\(lim\))、根据题目设出来的状态(例如数字出现的个数,模 \(m\) 的余数等等)。

模板:

int dp(int x,bool zer,bool lim,...){
  if(x==0)return ...;
  if(!~f[x][zer][lim][...])return f[x][zer][lim][...]; // 记忆化
  int res=0;
  for(int i=0;i<=(lim?num[x]:9);i++){
    if(zer&&i==0)res+=dp(x-1,1,lim&&i==num[x],...); // 是前导零
    else res+=dp(x-1,0,lim&&i==num[x],...); // 不是前导零
  } // 有时我们不关心是不是前导零,此时这两种情况可以合并
  return f[x][zer][lim][...]=res;
}
posted @ 2022-02-27 19:28  registerGen  阅读(35)  评论(0)    收藏  举报