【题目大意】
问在A~B之间有多少个 任意相邻两位的差都大于等于2 的数。
【题解】
一看这个数据范围,就知道是要用数位dp了。
显然,题目可以转化成 在1~n 中有多少个windy数。然后用solve(B)-solve(A-1)来求解。于是,现在的问题就是如何solve。
可以将位数比n要少的数用数位dp求解,因为位数如果小于n的位数的话,这个数就可以保证绝对比n小,然后再单独统计一下位数与n一样的即可,具体实现方法就看代码吧。
#include <cstdio>
#include <cstring>
int A,B;
int f[20][10];//f[i][j]表示第i位的数字为j的方案数
inline int abs(int x){return x>0?x:-x;}
void work()//数位dp
{
for(int i=0;i<=9;i++)
f[1][i]=1;
for(int i=2;i<=10;i++)
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++)
if(abs(j-k)>=2)f[i][j]+=f[i-1][k];
}
int count(int x)
{
if(x<10)return x;
int a[20],tot(0),ans(0);
while(x>0)a[++tot]=x%10,x/=10;//把x的每一位拆开存下来
for(int i=1;i<tot;i++)//对于位数小于n的直接统计
for(int j=1;j<=9;j++)
ans+=f[i][j];
//接下来统计位数与n一样的
//若最高位的数字小于a[1],那么无论后面是什么这个数都小于n
for(int i=1;i<a[tot];i++)
ans+=f[tot][i];//于是直接统计最高位填的数比a[1]小时的解
for(int i=tot-1;i>=1;i--)//然后再看一下第1位填a[1]时的情况
{//类似上面,先统计这一位填的数比a[i]要小时的解
for(int j=0;j<a[i];j++)
if(abs(j-a[i+1])>=2)ans+=f[i][j];
//然后再看一下这一位填a[i]是否合法
if(abs(a[i]-a[i+1])<2)break;//如果不合法,后面就没必要看了
}
return ans;
}
int main()
{
scanf("%d %d",&A,&B);
work();
printf("%d",count(B+1)-count(A));
//因为count里面没有讨论x是否是windy数,可以手动+1来避免讨论x
}