例题
数位dp实质是记忆化搜索
比如给出一个区间[l,r]
要你求[l,r]中有多少个数是3的倍数
for(int i=l;i<=r;i++){
if(i%3==0) ans++;
}
但是这样时间复杂度为o(r-l-1)接近于O(n),但如果判断的条件比较复杂,很容易超时
所以我们考虑数位dp
什么是数位dp
数位dp是对每个数位单独考虑,枚举可能的状态,记录一个答案,在结尾进行记录,方便记忆化,然后return 就行了
ll dfs(int dep,bool limit,int a,int b,int c,int d){
if(dep==0) return 1;
if(!limit&&dp[dep][a][b][c][d]!=-1) return dp[dep][a][b][c][d];
int up=limit?num[dep]:9;
ll res=0;
for(int i=0;i<=up;i++){
if(d==10&&i==0) res+=dfs(dep-1,limit&&i==up,10,10,10,10);
else
{
if(K==2){
if(i==d) continue;
res+=dfs(dep-1,limit&&i==up,b,c,d,i);
}
if(K==3){
if(i==d||i==c) continue;
res+=dfs(dep-1,limit&&i==up,b,c,d,i);
}
if(K==4){
if(i==b||i==c||i==d) continue;
res+=dfs(dep-1,limit&&i==up,b,c,d,i);
}
if(K==5){
if(i==a||i==b||i==c||i==d) continue;
res+=dfs(dep-1,limit&&i==up,b,c,d,i);
}
}
}
if(!limit){
dp[dep][a][b][c][d]=res;
}
return res;
}
具体每道题不一样,要根据题目写状态
注意:
if(d==10&&i==0) res+=dfs(dep-1,limit&&i==up,10,10,10,10);
答案的套路: s o l v e ( r ) − s o l v e ( l − 1 ) solve(r)-solve(l-1) solve(r)−solve(l−1)