数位dp:
dp[i][op][v]表示第i位上的数字为v,并且状态是op
所以小于等于n的满足条件的数量为ans=dp[位数][2][0]+dp[位数][0][0-最高位上的数字-1]+dp[位数][1][最高位上的数字]
其中op=0表示之前的数字没有和所给数字完全一样,也就是没有到上限,因此,这一位选0-9都可以,且op=0
op=1表示之前的数字和所给数字完全一样,也就是达到上香,这一位只能选0-这一位,当选原数字上的这个数时,op=1
当选其他数字时,op就可以为0了
op=2 表示前面全是先导0(如:00012),注意这里存在00000的情况,但由于后续的相减,减掉了,不用做特别处理
我们就需要用ansb-ans(a-1)即为答案
#include<bits/stdc++.h>
using namespace std;
int a,b,w[11];
int dp[11][3][11];
int dpp(int i ,int op ,int v)
{
if(dp[i][op][v]!=-1) return dp[i][op][v];
if(i==1) return 1;
if(i==0) return 0;
dp[i][op][v]=0;
if(op==0)
{
for(int j=0;j<=9;j++)
if(v-j>=2 || j-v>=2)
dp[i][op][v]+=dpp(i-1,op,j);
return dp[i][op][v];
}
if(op==1)
{
for(int j=0;j<w[i-1];j++)
if(v-j>=2 || j-v>=2)
dp[i][op][v]+=dpp(i-1,0,j);
if(w[i-1]-v>=2 || v-w[i-1]>=2)
dp[i][op][v]+=dpp(i-1,1,w[i-1]);
return dp[i][op][v];
}
if(op==2)
{
for(int j=1;j<=9;j++)
dp[i][op][v]+=dpp(i-1,0,j);
dp[i][op][v]+=dpp(i-1,2,0);
return dp[i][op][v];
}
}
int main()
{
scanf("%d%d",&a,&b);
int cnt=0,aa=b,bb=a-1;
while(aa>0)
{
w[++cnt]=aa%10;
aa/=10;
}
memset(dp,-1,sizeof(dp));
int ansa=0;
ansa+=dpp(cnt,2,0);
for(int i=1;i<w[cnt];i++)
ansa+=dpp(cnt,0,i);
ansa+=dpp(cnt,1,w[cnt]);
cnt=0;
memset(dp,-1,sizeof(dp));
while(bb>0)
{
w[++cnt]=bb%10;
bb/=10;
}
if(bb=0) cnt=1,w[1]=0;
int ansb=0;
ansb+=dpp(cnt,2,0);
for(int i=1;i<w[cnt];i++)
ansb+=dpp(cnt,0,i);
ansb+=dpp(cnt,1,w[cnt]);
ansb=max(ansb,1);
ansa=max(ansa,1);
printf("%d\n",ansa-ansb);
return 0;
}

本文深入解析数位DP算法,一种用于解决数字问题的动态规划方法。通过递归地计算每一位数字的状态,有效统计满足特定条件的数字数量。适用于求解数字范围内的各种约束问题。
798

被折叠的 条评论
为什么被折叠?



