初级数位DP--hdu2089

来源:互联网 发布:淘宝装修图片轮播尺寸 编辑:程序博客网 时间:2024/06/08 03:05
hdu2089 不要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
 

Author
qianneng


这是最基础的数位DP.
题意为:
对于一个整数n,如果(任何一位上是4)||(第i位为6,,第i+1位为2),则这个数是不吉利的
题目要求求n到m有多少数是吉利的。

首先想到暴力,枚举n到m的每个数,判断是否合法,这样应该会超时。
然后我们可以发现有许多数是属于同一种类型的,并不用枚举每一个;
这样就想到用数位dp来做。
个人比较喜欢用dfs+记忆化来做数位dp的题目
只要用dp[i][j]来记录还剩下需要决策的长度i前一位是否填的是6的吉利数的个数
枚举当前位上取什么数,然后进行转移,用flag1记录前一位是否为6.
sum+=dfs(len-1,i==6);
此题看似是解决了,但还有一个问题,最后生成的数会不会超出这个范围?
可能的...
所以我们要用flag2来记录前面几位中是否都是达到上限的,如果是,那这位的上限就是digit[i],否则0~9都可以取。
这样就将这道经典数位DP解决了。
如果有问题详见代码...


#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;int dp[10][2],digit[10];int dfs(int len,bool flag1,bool flag2){    if(!len) return 1;    if(!flag2 && dp[len][flag1]!=-1) return dp[len][flag1];    int sum=0,top;    if(flag2) top=digit[len];    else top=9;    for(int i=0;i<=top;i++){        if(i==4 || flag1 && i==2) continue;        sum+=dfs(len-1,i==6,flag2&&(i==top));    }    if(!flag2) dp[len][flag1]=sum;    return sum;}int solve(int n){    int len=0;    while(n){        digit[++len]=n%10;        n/=10;    }    return dfs(len,false,true);}int main(){    int a,b;    memset(dp,-1,sizeof(dp));    while(scanf("%d%d",&a,&b),a||b){        printf("%d\n",solve(b)-solve(a-1));    }    return 0;}


原创粉丝点击