杭电 hdu 2089 不要62【数位dp】【入门】

不要62

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 65269    Accepted Submission(s): 25991

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 100 0 0

Sample Output

80

 暴力破解即可

但数位dp更省时

暴力破解需要从n数到m

而dp则是只需要数log(10)n+log(10)m就够了

比如 5234

首先数5000内的不含62,4的个数

这个不用一个一个数,之前由于打表 了,所以只需要

a[0][4]+a[1][4]+a[2][4]+a[3][4]+a[4][4]即可

然后加1-200

然后加1-30

然后加1-4的个数即可

 #include<bits/stdc++.h>
 using namespace std;
 #define ll long long
 #define mx 1000011
 ll a[10][9];
 ///a[j][i]:表示长度为i且开头数字为j的个数
  

 int init(){///预处理,打表一下
     a[0][0]=1;
    for(int i=1;i<9;i++){///i位数字

        for(int j=0;j<10;j++){

            for(int k=0;k<10;k++){

                if(!(k==2&&j==6)&&j!=4)
                a[j][i]+=a[k][i-1];
            }
        }
    }

 }
 int b[10];
 ll sovle(int n){
    int i=1;
    memset(b,0,sizeof(b));
    while(n){
        b[i++]=n%10;
        n/=10;
    }
    i--;
    ll ans=0;
    for(;i>=1;i--){///从高位开始遍历
        for(int j=0;j<b[i];j++){
            if(!(j==2&&b[i+1]==6)&&j!=4)
            ans+=a[j][i];
        }
        if(b[i]==4||(b[i]==2&&b[i+1]==6))break;
    }
    return ans;
 }
 int main()
 {
    init();
    ll a,b;
    while(cin>>a>>b,a||b){

        printf("%lld\n",sovle(b+1)-sovle(a)); 
    } 
     return 0;
 }

贴上去一个链接,这个讲的比较好

https://blog.csdn.net/mengxiang000000/article/details/50614873

 

 

 

点赞