这题是一道数位DP
f[i][j]表示总共有i位数字,其中最高位数字为j的windy数个数
f[i][j]+=f[i-1][k] 其中,k为0~9中的数且|j-k|>=2
那么接下来就根据题目所给的A,B用前缀和相减就好了。
那对于A/B如何求前缀和呢,下面用A来说明
一。若一个数 的位数比A少,那么这个数一定比A小,直接加上方案数。
二。位数相同:
这个数的最高位 比 A的最高位小,这个数一定比A小,同样直接加上方案数。
接下来固定住这个数的最高位与A相同吗,加上剩下的方案数,
再固定次高位,次次高位······
这样就能保证我们加的方案数的数一定小于A
因为题目的性质,一个windy数再减少一位还是windy数,一个非windy数再减少一位不可能再出现windy数,所以,当我的A在某一位开始不满足windy数了,那么接下来的位一定也不满足windy数了,break就好。
#include<cstdio>
#include<cstdlib>
#include<cstring>
int f[15][15];
int wei[15],weit=0;
int myabs(int soy)
{
if(soy<0)return -soy;
return soy;
}
int ji(int x)
{
weit=0;
int num=0;
while(x>0)
{
wei[++weit]=x%10;
x/=10;
}
for(int i=1;i<weit;i++)
{
for(int j=1;j<=9;j++)
{
num+=f[i][j];
}
}
for(int i=1;i<wei[weit];i++)
num+=f[weit][i];
for(int i=weit-1;i>=0;i--)
{
for(int j=0;j<wei[i];j++)
if(myabs(j-wei[i+1])>=2)num+=f[i][j];
if(myabs(wei[i]-wei[i+1])<2)break;
}
return num;
}
int main()
{
int A,B;
scanf("%d%d",&A,&B);
for(int i=0;i<=9;i++)
f[1][i]=1;
for(int i=2;i<=12;i++)
for(int j=0;j<=9;j++)
{
for(int k=0;k<=9;k++)
{
if(myabs(j-k)>=2)
{
f[i][j]+=f[i-1][k];
}
}
}
printf("%d\n",ji(B+1)-ji(A));
}