题意:输出n<=i<=m范围内不含有4与连续数字62的i的个数。
题解:数位dp
1.dp[i][j]表示满足题意的最高位为j的i位数的个数。
2.dp[i][j] = Σ(dp[i-1][k])(0<=k<=9 && k != 4 && !(j == 6 && k == 2))
3.重要的是如何通过dp数组获得所需的答案。
(1)举例子a = 45 , b = 53 ,那么需要知道1~a-1和1~b的数,然后作差就是答案。
计算1~b的数:dp[2][0]+dp[2][1]+dp[2][2]+dp[2][3]+dp[2][4]算出十位数小于5的数。
dp[1][0]+dp[1][1]+dp[1][2]算出个位数小于3的数。
这样会漏掉53,因此若要得到1~x的数,需用这样的方法计算1~1+x的数。
统计的时候注意4和62。例如统计1~a-1的数时只需统计十位数小于4的数,因为当十位数为4时,个位数是多少都不计入总数。
同理,若前一位是6,这一位是2时,不必继续统计下一位及之后的数了。
#include<iostream>
#include<cstring>
#include<math.h>
#include<algorithm>
#include<map>
#include<stdio.h>
#include<queue>
#include<stack>
#define inf 0x3f3f3f3f
using namespace std ;
int dp[10][10] ;
void cal()
{
int i , j , k ;
memset(dp , 0 , sizeof(dp)) ;
dp[0][0] = 1 ;
for(i = 1 ; i <= 7 ; i ++)
for(j = 0 ; j <= 9 ; j ++)
{
if(j == 4)
continue ;
for(k = 0 ; k <= 9 ; k ++)
if(j == 6 && k == 2)
continue ;
else
dp[i][j] += dp[i-1][k] ;
}
}
int count(int x)
{
int i , j , k ;
int len = 1 , a[10] ;
int ans = 0 ;
while(x > 0)
{
a[len] = x % 10 ;
x /= 10 ;
len ++ ;
}
a[0] = a[len] = 0 ;
for(i = len - 1 ; i >= 1 ; i --)
{
for(j = 0 ; j < a[i] ; j ++)
{
if(a[i + 1] == 6 && j == 2)
continue ;
ans += dp[i][j] ;
}
if(a[i] == 4 || a[i + 1] == 6 && a[i] == 2)
break ;
}
return ans ;
}
int main()
{
int a , b ;
int ans1 , ans2 ;
cal() ;
while(scanf("%d%d" , &a , &b) && !(a == 0 && b == 0))
{
ans1 = count(b + 1) ;
ans2 = count(a) ;
ans1 -= ans2 ;
printf("%d\n" , ans1) ;
}
}