数位DP + 特殊数字的限制
题意:
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
思路:
最开始可以想到直接一个一个数字去试试,找一找是否满足情况,这是笨办法,也会超时。
而数位DP可以用数字的特性去解决:
- 一个数字有位数的特性
- 一个数字可以拆分为不同的数字的和例如:314可以拆分为:0~99,100~199,200~299,300~309,310~314
利用上边的特性定义: dp[i][j] 为数字的第i位以j数字开头的满足题意的个数
那么便有: dp[i][j]=∑9j=0dp[i−1][j] ,而62 和 4 只需直接加上限制条件就行。
- 其中一个点需要注意的是,当高位算了之后算低位上的数字,其实是在高位的基础上算的,所以高位是4或者62的时候需要跳出,已经不存在满足的数字了。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m;
int dp[10][10];
void 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];
}
}
}
}
int solve(int a)
{
int temp[10];
int pos = 0;
while(a) {
temp[++pos] = a%10;
a /= 10;
}
temp[pos+1] = 0;
int ans = 0;
for(int i = pos;i >= 1; i--) {
for(int j = 0;j < temp[i]; j++) {
if(j != 2 || temp[i+1] != 6)
ans += dp[i][j];
}
if(temp[i] == 4 || (temp[i+1] == 6 && temp[i] == 2)) break;
}
return ans;
}
int main(int argc, char const *argv[])
{
//freopen("in.txt","r",stdin);
DP();
while(scanf("%d%d",&n,&m) != EOF) {
if(n == 0 && m == 0) break;
printf("%d\n",solve(m+1)- solve(n));
}
return 0;
}