Time Limit: 1 Sec  Memory Limit: 162 MB

Description

  windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?

Input

  包含两个整数,A B。

Output

  一个整数

Sample Input

【输入样例一】
1 10
【输入样例二】
25 50

Sample Output

【输出样例一】
9
【输出样例二】
20

HINT

【数据规模和约定】

100%的数据,满足 1 <= A <= B <= 2000000000 。

Source

递推方程很好想,用f[i][j]表示i位数第i位为j的数的个数

对于一个数想求比它小的有多少个windy数,用752举例

首先求1~699

接着700~749

最后750~752另一件事,为什么要记录并递推f[i][0],并且把f[1][0]标记为1

对于702的递推如果不递推f[2][0]就无法统计。

对于20如果不把f[1][0]标记为1也无法统计。

而且由于求的是一段区间,所以答案不会改变。

#include<cstdio>
typedef long long ll;
ll f[11][10];
int cf[11];
int jdz(int a)
{
    return a>0?a:-a;
}
ll cnt(ll a)
{
    int len=1;
    ll re=0;
    for(;a;len++,a/=10) cf[len]=a%10;
    for(int i=2;i<len;i++) re+=f[i-1][0]+f[i-1][1];//对于最高位0的其实并不需要保证第i-1不为1,0.所以这一部分会少统计
    for(int sg=-2,ssg=-10,i=len-1;i;i--)
    {
        for(int j=cf[i]-1;j>=0;j--)
            if(sg-j>1||j-sg>1) re+=f[i][j];
        if(sg<0) sg=cf[i];
        else ssg=sg,sg=cf[i];
        if(jdz(ssg-sg)<2) break;
    }
    return re;
}
int main()
{
    ll l,r;
    scanf("%lld%lld",&l,&r);
    for(int i=0;i<10;i++) f[1][i]=1;
    for(int i=2;i<=10;i++)
        for(int j=0;j<10;j++)
            for(int k=0;k<10;k++)
                if(j-k>1||k-j>1) f[i][j]+=f[i-1][k];
    printf("%lld\n",cnt(r+1)-cnt(l));
    return 0;
}