杭州人称那些傻乎乎粘嗒嗒的人为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
这是一道较为简单的数位DP裸题,虽说简单,但是一开始理解起来会很困难
题中说要在给定集合里找到不满足条件的数的个数,当数据范围比较大的时候,暴力是一定不可能的
这时候我们利用数位DP来解决此类问题
首先,我们已知[a, b],那么可以将这个区间分解成[0, a]和[0, b],那么只需求[0, b] - [0, a - 1]之间满足的数的个数即可
然后将a和b的每一位的数存到数组a中各个元素,并得到位数length,然后再定义一个二维dp数组
至此,准备工作完成
接下来,我们进行记忆化搜索,利用深度优先搜索的原理,记录上一位是否为6和枚举这一位,如果没有限制的话很好办,直接枚举就可以了,但是这样可能会超空间,因此我们每次都必须要判断是否有最大的限制,比如说最大是455,那么百位的遍历范围只有0到4,十位和个位同理,当没有限制时遍历直接0到9,同时已经计算过的状态不会计算第二次,深度优先遍历到最底层、然后向上传递返回值,满足条件的会存放到dp数组中,定义一个变量计算它们的和,函数参数设定以及dp数组设定不唯一,具体见代码
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int a, b, shu[100];
long long dp[20][2];
long long dfs(int len, int pre, int state, bool limit){
if(len == -1)
return 1;
if(!limit && dp[len][state] != -1)
return dp[len][state];
int maxq = limit ? shu[len] : 9;
long long ans = 0;
for(int i = 0; i <= maxq; i++){
if(pre == 6 && i == 2)
continue;
if(i == 4)
continue;
ans += dfs(len - 1, i, i == 6 ? 1 : 0, limit && i == shu[len]);
}
if(!limit)
dp[len][state] =ans;
return ans;
}
int solve(int x){
memset(shu, 0, sizeof(shu));
int k = 0;
while(x){
shu[k++] = x % 10;
x /= 10;
}
return dfs(k - 1, 0, 0, true);
}
int main()
{
while(scanf("%d%d", &a, &b) && a != 0 && b != 0){
memset(dp, -1, sizeof(dp));
cout << solve(b) - solve(a - 1) << endl;
}
return 0;
}