SCOI 2009 windy数 题解

题目传送门

题目大意: 问在 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 A1 的答案。

然后可以将位数比 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
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值