HDU2089 不要62
题目描述:
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
输入描述:
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
输出描述:
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
样例输入:
1 100
0 0
样例输出:
80
首先暴力...枚举每个数,log n枚举每一位判断是否符合,复杂度n log n,爆炸
正解~数位dp
求解区间l - r的答案,可以转换为求1 - r和1 - (l - 1)做差
那问题转换成了如何在区间1 - n中求解答案,问题就变得简单了
我们用dp[i][j]表示。一个长度为i的数字,最高位数字是j,有多少个符合条件的数
假设我们已经处理这个数字,考虑如何统计答案。
比如我们当前在统计第i位的答案,如果这个数字第i位是k,那么,第i位是[1 , i - 1]的其他数字一定都在范围内,直接统计
那么对于第i位等于k的数字?
第i位等于k的数字,并不是后面的位数可以随意了,后面的数字小于给定数字的范围。所以我们可以通过枚举
下一位的数字是什么,来统计当前位等于给定数字的数字。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 6 #define RI register 7 using namespace std; 8 typedef long long ll; 9 10 #define max(a,b) ((a) > (b) ? (a) : (b)) 11 #define min(a,b) ((a) < (b) ? (a) : (b)) 12 13 inline void read(int &x) 14 { 15 x = 0; 16 bool flag = 0; 17 char ch = getchar(); 18 while(ch < '0' || ch > '9') 19 { 20 if(ch == '-') flag = 1; 21 ch = getchar(); 22 } 23 while(ch >= '0' && ch <= '9') 24 { 25 x = x * 10 + ch - '0'; 26 ch = getchar(); 27 } 28 if(flag) x *= -1; 29 } 30 31 int d[10],n,m; 32 int dp[10][10]; 33 34 void init() 35 { 36 dp[0][0] = 1; 37 for(int i = 1;i <= 7;i ++) 38 for(int j = 0;j <= 9;j ++) 39 for(int k = 0;k <= 9;k ++) 40 if(j != 4 && !(j == 6 && k == 2)) 41 dp[i][j] += dp[i - 1][k]; 42 } 43 44 int solve(int n) 45 { 46 int len = 0; 47 int ans = 0; 48 while(n) 49 { 50 d[++ len] = n % 10; 51 n /= 10; 52 } 53 d[len + 1] = 0; 54 for(int i = len; i >= 1;i --) 55 { 56 for(int j = 0; j < d[i];j ++) 57 { 58 if(d[i + 1] != 6 || j != 2) 59 ans += dp[i][j]; 60 } 61 if(d[i] == 4 || (d[i + 1] == 6 && d[i] == 2)) 62 break; 63 } 64 return ans; 65 } 66 67 int main() 68 { 69 init(); 70 while(scanf("%d%d",&m,&n) == 2) 71 { 72 if(n == 0 && m == 0) break; 73 printf("%d ",solve(n + 1) - solve(m)); 74 } 75 return 0; 76 }