【hdu2089】不要62 数位dp

题目描述

求 $[n,m]$ 内不包含数位串 “4” 和 “62” 的数的个数。

输入

输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。

输出

对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

样例输入

1 100
0 0

样例输出

80


题解

数位dp

设 $f[i][j]$ 表示 $i$ 位数,最高位为 $j$ ,且不出现数位串 “4” 和 “62” 的数的个数。

那么直接枚举上一位,根据是否构成非法串进行转移。

然后对于每组询问转化为 $[1,a)$ 的区间相减,每个区间进行数位dp,先计算位数不满的,再从高位到低位枚举,当前位如果小于 $a$ 的这一位则一定满足区间条件。如果这一位和上一位不构成 “62” 则统计到答案中。

注意当上一位与当前位组成“62”时及时跳出循环。

(貌似本题暴力可过?...)

#include <cstdio>
int f[8][10] , b[8];
void init()
{
	int i , j , k;
	f[0][0] = b[0] = 1;
	for(i = 1 ; i < 8 ; i ++ )
	{
		b[i] = b[i - 1] * 10;
		for(j = 0 ; j < 10 ; j ++ )
			for(k = 0 ; k < 10 ; k ++ )
				if(j != 4 && !(j == 6 && k == 2))
					f[i][j] += f[i - 1][k];
	}
}
int calc(int n)
{
	int i , j , di = 1 , last = 0 , now , ans = 0;
	for(i = 1 ; b[i] <= n ; i ++ )
		for(j = 1 ; j < 10 ; j ++ )
			ans += f[i][j];
	for( ; i ; i -- )
	{
		now = n / b[i - 1] % 10;
		for(j = di ; j < now ; j ++ )
			if(!(last == 6 && j == 2))
				ans += f[i][j];
		if(now == 4 || (last == 6 && now == 2)) break;
		di = 0 , last = now;
	}
	return ans;
}
int main()
{
	init();
	int n , m;
	while(~scanf("%d%d" , &n , &m) && !(n == 0 && m == 0))
		printf("%d
" , calc(m + 1) - calc(n));
	return 0;
}
原文地址:https://www.cnblogs.com/GXZlegend/p/7814542.html