HDU 2089 数位dp 不要62

不要62

题目链接: 传送门

其实是做topcoder的时候碰到不会的题,看人家说要用数位dp,所以拿http://acm.hdu.edu.cn/showproblem.PHP?pid=2089来学习了一下

数位dp适合在一段数的区间内找出满足某些条件的数的个数,这个时候往往不能之间遍历,肯定会超时,则一般使用数位dp来解决

数位dp的常见形式是dp[i][j],表示开头是j的i位数满足条件的有多少个,当然也有其他dp[i][j][k]等等,但i,j,k都很小,不会像直接遍历那么耗时

像这道题的话,知道了dp[i][j]表示的是啥,就能列出状态转移方程(稍微认真看就能理解的):

[cpp]  view plain  copy
  1. for(int i=1;i<=7;i++)  
  2.     {  
  3.         for(int j=0;j<10;j++)//枚举第i位可能出现的数  
  4.         {  
  5.             for(int k=0;k<10;k++)//枚举第i-1位可能出现的数  
  6.             {  
  7.                 if(j!=4&&!(j==6&&k==2))  
  8.                     dp[i][j]  += dp[i-1][k];  
  9.             }  
  10.         }  
  11.     }  



 

更加具体的介绍可以参考:http://wenku.baidu.com/link?url=o3ER_gVCyB0qcKthM-Y8vPtAGZ_u5bzOu_gUCUhPcXC6YfaSDgtBSXNEEvvGvSzyuDE9TULcPNsDrRd9IUtQVHeKUVrnPUjyfWjCly_J7Xq


以下附上ac这题的代码:

[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <string>  
  3. #include <string.h>  
  4. #include <algorithm>  
  5. using namespace std;  
  6. int dp[10][10];  
  7. void init()  
  8. {  
  9.     memset(dp,0,sizeof(dp));  
  10.     dp[0][0] = 1;  
  11.     for(int i=1;i<=7;i++)  
  12.     {  
  13.         for(int j=0;j<10;j++)//枚举第i位可能出现的数  
  14.         {  
  15.             for(int k=0;k<10;k++)//枚举第i-1位可能出现的数  
  16.             {  
  17.                 if(j!=4&&!(j==6&&k==2))  
  18.                     dp[i][j]  += dp[i-1][k];  
  19.             }  
  20.         }  
  21.     }  
  22. }  
  23. int solve(int n)  
  24. {  
  25.     init();  
  26.     int digit[10];  
  27.     int len = 0;  
  28.     while(n>0)  
  29.     {  
  30.         digit[++len] = n%10;  
  31.         n/=10;  
  32.     }  
  33.     digit[len+1]=0;  
  34.     int ans = 0;  
  35.     for(int i=len;i;i--)  
  36.     {  
  37.         for(int j=0;j<digit[i];j++)  
  38.         {  
  39.             if(j!=4&&!(digit[i+1]==6&&j==2))  
  40.                 ans+=dp[i][j];  
  41.         }  
  42.         if(digit[i]==4||(digit[i]==2&&digit[i+1]==6))  
  43.             break;  
  44.     }  
  45.     return  ans;  
  46. }  
  47. int main()  
  48. {  
  49.     int l,r;  
  50.     while(cin>>l>>r)  
  51.     {  
  52.         if(l+r==0)  
  53.             break;  
  54.         else  
  55.             cout<<solve(r+1)-solve(l)<<endl;  //因为solve没有考虑r的情况所以要从r+1开始才是正确结果。
  56.     }  
  57.     return 0;  
  58.   
  59. }  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值