Description
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
Input
包含两个整数,A B。
Output
一个整数
Sample Input
【输入样例一】
1 10
【输入样例二】
25 50
1 10
【输入样例二】
25 50
Sample Output
【输出样例一】
9
【输出样例二】
20
9
【输出样例二】
20
HINT
【数据规模和约定】
100%的数据,满足 1 <= A <= B <= 2000000000 。
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~数位DP~
用f[i][j]表示第i位上填j时的方案数,那么f[i][j]=sum{f[i-1][k]},其中abs(j,k)>=2。
要得到[a,b]的答案,我们可以用ans[1,b]-ans[1,a-1],所以要计算的就是[1,u]的答案。
我们可以把它分为两个部分(设数u的第i位为x[i],总位数为tot):
(1)计算首位不为x[tot]的种类数,枚举位数,首位贡献的答案是f[tot][1...x[tot]-1],其余每位贡献的答案是f[i][1...9];
(2)计算首位为x[tot]的种类数,从高往低枚举,先计算完第i位<x[i]的种类数,再以第i位是x[i]为基准往下计算。这里注意,如果abs(x[i],x[i+1])<2,就不用再往下计算。
但是用上面的方法计算出来的是1~u-1的种类数,所以我们在输出的时候要输出ans[1,u-1]。
答案一定小于2*10^9,int就够了。
#include<cstdio>
int a,b,f[12][10];
int abs(int u)
{
return u>0 ? u:-u;
}
int cal(int u)
{
if(!u) return 0;
int x[12],tot=0,ans=0;
while(u) x[++tot]=u%10,u/=10;
for(int i=1;i<x[tot];i++) ans+=f[tot][i];
for(int i=tot-1;i;i--)
for(int j=1;j<=9;j++) ans+=f[i][j];
for(int i=tot-1;i;i--)
{
for(int j=0;j<x[i];j++)
if(abs(x[i+1]-j)>=2) ans+=f[i][j];
if(abs(x[i+1]-x[i])<2) break;
}
return ans;
}
int main()
{
scanf("%d%d",&a,&b);
for(int i=0;i<=9;i++) f[1][i]=1;
for(int i=1;i<=11;i++)
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++)
if(k>j+1 || j>k+1) f[i][j]+=f[i-1][k];
printf("%d\n",cal(b+1)-cal(a));
return 0;
}