hdu 2089 数位dp

题意:输出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) ;	
	}
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值