SCOI 2009 windy数 题解

       题目传送门

【题目大意】

        问在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
}

猜你喜欢

转载自blog.csdn.net/a_forever_dream/article/details/88551799