hdu 2089 不要62

来源:互联网 发布:微信多开软件苹果版 编辑:程序博客网 时间:2024/06/08 09:08

不要62

Problem Description

杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。

 


Input

输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。

 


Output

对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

 


Sample Input

1 1000 0

 


Sample Output

80

 


解题思路

数位dp,ural上有一个更简单的数位dp的题1009. K-based Numbers,我博客中也有题解http://blog.csdn.net/ly59782/article/details/53328063,可以先看看ural上简单一点的那个题目。,

同样的,以什么为结尾并不好思考,我们还是考虑以什么为开头,然后不断往高位插入数。

那么dp[i][j] 就表示前 i 位以 j 打头的合格数

因为不能有4 出现, 所以 dp[i][4] = 0

那么 dp[i][j] =  dp[i-1][k]  ( j!= 6 || k != 2) 

这样我们就有了 0~9,10~19,20~29,........,100~199,200~299…………这些区间内的合格数了, 但是由于我们要求的区间不是这种简单的区间,例如要求10~235区间内合格数目,显然是 先求出0~235,0~9,然后相减。那么怎么处理像0~235这种区间呢


先求出0打头的三位数0XX(即从001~099)+

然后求1打头的三位数1XX(即从100~199)+

2打头的不考虑

这样我们就有了从0~199范围内的合格数了,然后从200~235 其实就相当于从0~35这个范围。

下面求0~35

0打头的两位数 0X+

1打头的两位数1X+

2打头的两位数2X

3打头的不考虑

这样我们0~199,200~229范围内的都有了,最后还剩下 30~35,也就相当于求0~5这个区间,同样的

0打头的1位数+1打头的1位数……

5打头的不考虑

这里出现了问题, 5打头的不考虑不是少了一个数吗?由于前面都不考虑,这里为了简化程序,不做特判,所以也不考虑,但是不能让答案少一个数呀? 所以我们传区间的时候可以+1,求0~235相当于求了0~234,那么相求0~235,传参传0~236就搞定了


代码

#include <iostream>#include <cstdio>#include <map>#include <cmath>#include <string.h>#include <algorithm>#include <set>#include <sstream>using namespace std;const int maxn = 0;const int INF = 0x3f3f3f3f;int dp[8][10];int d[8];int n,m; int f(int n){        int ans = 0;        int len = 0;        ///化成字符串形式,并倒置存放        while(n){            d[++len] = n%10;            n /= 10;        }        d[len+1] = 0;///避免上次结果影响        for(int i = len; i>=1;--i){                        for(int j = 0; j<d[i]; ++j){                if(d[i+1]!= 6 || j!=2)                    ans += dp[i][j];            }            if(d[i]==4 || (d[i+1] ==6 && d[i]==2)) break;        }        return ans;    }int main(){    ///初始化dp    dp[0][0] = 1;    for(int i = 1 ;i<=7;++i){        for(int j = 0 ;j<=9;++j)            for(int k = 0; k<=9; ++k)                if(j!=4 && !(j==6&&k==2))                    dp[i][j] += dp[i-1][k];    }    while(scanf("%d%d",&n,&m)!=EOF && !(n==0 && m==0)){        printf("%d\n",f(m+1)-f(n));    }    return 0;}


1 0