1.数位dp应用场景
- 一种计数用的dp,一般就是要统计一个区间[l,r]内满足一些条件数的个数,通常情况下l和r都比较大。所谓数位dp,字面意思就是在数位上进行dp。数位型dp的核心思想是在数位上不进行暴力搜索,而是采取记忆化搜索的形式,然后进行求值。
2.经典问题
2.1 一个数位的数位型dp
- 在 1 至 n 中,有多少个数的数位中包含数字 9?
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
int dfs(vector<int>& dp,vector<int>&dig,int pos,bool flag){
if(pos<0) return 1;
if(!flag&&dp[pos]!=-1) return dp[pos];
int mx=flag?dig[pos]:9;
int res=0;
for(int i=0;i<=mx;i++){
if(i!=9){
res+=dfs(dp,dig,pos-1,flag&&i==dig[pos]);
}
}
if(!flag) dp[pos]=res;
return res;
}
int main()
{
int n;
vector<int> dig;
cin>>n;
int t=n;
while(t){
dig.push_back(t%10);
t=t/10;
}
vector<int> dp(dig.size(),-1);
cout<<n-dfs(dp,dig,dig.size()-1,true)+1;
return 0;
}
2.2 包含特定数值的数位型dp
- 在 1 至 n 中,有多少个数的数位中包含数字 62或者4?//做法和上面差不多相同
- 参考代码:
#include<bits/stdc++.h>
using namespace std;
int dfs(vector<vector<int>>& dp,vector<int>&dig,int pos,bool sta,bool flag){
if(pos<0) return 1;
if(!flag&&dp[pos][sta]!=-1) return dp[pos][sta];
int mx=flag?dig[pos]:9;
int res=0;
for(int i=0;i<=mx;i++){
if(i==4) continue;
if(sta&&i==2) continue;
res+=dfs(dp,dig,pos-1,i==6,flag&&i==dig[pos]);
}
if(!flag) dp[pos][sta]=res;
return res;
}
int main()
{
int n