题目大意: 问在 A A A ~ B B B 之间有多少个 任意相邻两位的差都大于等于 2 2 2 的数。
【题解】
一看这个数据范围,就知道是要用数位 d p dp dp 了。
显然答案可以差分成 1 1 1 ~ B B B 的答案减去 1 1 1 ~ A − 1 A-1 A−1 的答案。
然后可以将位数比 n n n 要少的数用数位 d p dp dp 求解,因为位数如果小于 n n n 的位数的话,这个数就可以保证绝对比 n n n 小,然后再单独统计一下位数与 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-1;//不算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[tot]小时的解
for(int i=tot-1;i>=1;i--)//然后再看一下第1位填a[tot]时的情况
{//类似上面,先统计这一位填的数比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
}