数位DP 不要62

时间:2023-03-09 17:07:57
数位DP 不要62

数位DP的问法是从某个数到某个数的区间里,求出满足题目要求的个数;

如本题所说的不要62和4,就是求出这个区间内,满足这一条件的数;

比如问 6 199的这个区间内满足条件的数,那么就求出1到199满足的数减去1到(6-1)满足的数即可;

那么 具体怎么从操作呢?

首先,我们先求出这个数的a[]数组,求出每一位具体是什么数(dfs的时候需要用到)

然后开始dfs,从最高位开始逐步深搜下来,将不满足的情况过滤掉,然后将满足普遍情况的值保存下来

那么哪些是普遍情况呢:就是无论不会被限制条件限制掉的状态的数

最后枚举到最低位-1,再层层回溯就好了,

本题中的体现形式是:!limit

 #include<cstdio>
#include<string.h>
using namespace std;
const int maxn=;
int dp[maxn][],a[maxn];
int dfs(int pos,int pre,int sta,bool limit)
{
if(pos==-) return ; //枚举到比最低为少一位的时候,就开始回溯
if(!limit&&dp[pos][sta]!=-) return dp[pos][sta]; //满足普遍情况的就可以直接用
//这是十分必要的,没有这一步的话跟普通dfs没什么区别
int up=limit?a[pos]:; //保存这个数的每一位的作用就体现在这里了
//假如这一位数是5,那么他枚举的数便不能超过这个数
int tmp=;
for(int i=;i<=up;i++){
if(i==) continue;
if(pre==&&i==) continue; //不满足的情况就过滤;
tmp+=dfs(pos-,i,i==,limit&&i==a[pos]);
}
if(!limit) dp[pos][sta]=tmp; //满足普遍情况就保存;
return tmp;
}
int solve(int n)
{
int pos=;
while(n){
a[pos++]=n%; //将这个数每一位的数保存下来;
n/=;
}
return dfs(pos-,-,,true);
}
int main()
{
int n,m;
memset(dp,-,sizeof(dp));
while(scanf("%d%d",&n,&m)!=EOF){
if(m==&&n==) break;
printf("%d\n",solve(m)-solve(n-));
}
return ;
}