题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555

Problem Description
The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would
add one point.

Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them?
 
Input
The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description.



The input terminates by end of file marker.
 
Output
For each test case, output an integer indicating the final points of the power.
 
Sample Input
  1. 3
  2. 1
  3. 50
  4. 500
 
Sample Output
  1. 0
  2. 1
  3. 15
  4. Hint
  5. From 1 to 500, the numbers that include the sub-sequence "49" are "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499",
  6. so the answer is 15.
  7.  
 
Author
fatboy_cw@WHU
 
Source

题意:

求0 到n的数中有多少个数字是含有‘49’的。

PS:

数位DP

//dp[i][j]:长度为i的数的第j种状态

//dp[i][0]:长度为i可是不包括49的方案数

//dp[i][1]:长度为i且不含49可是以9开头的数字的方案数

//dp[i][2]:长度为i且包括49的方案数

(转)状态转移例如以下

dp[i][0] = dp[i-1][0] * 10 - dp[i-1][1];  // not include 49  假设不含49且,在前面能够填上0-9 可是要减去dp[i-1][1] 由于4会和9构成49

dp[i][1] = dp[i-1][0];  // not include 49 but starts with 9  这个直接在不含49的数上填个9即可了

dp[i][2] = dp[i-1][2] * 10 + dp[i-1][1]; // include 49  已经含有49的数能够填0-9,或者9开头的填4



接着就是从高位開始统计



在统计到某一位的时候,加上 dp[i-1][2] * digit[i] 是显然对的。由于这一位能够填 0 - (digit[i]-1)

若这一位之前挨着49,那么加上 dp[i-1][0] * digit[i] 也是显然对的。

若这一位之前没有挨着49,可是digit[i]比4大,那么当这一位填4的时候,就得加上dp[i-1][1]

代码例如以下:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. typedef __int64 LL;
  7. LL dp[27][3];
  8. int c[27];
  9. //dp[i][j]:长度为i的数的第j种状态
  10. //dp[i][0]:长度为i可是不包括49的方案数
  11. //dp[i][1]:长度为i且不含49可是以9开头的数字的方案数
  12. //dp[i][2]:长度为i且包括49的方案数
  13. void init()
  14. {
  15. memset(dp,0,sizeof(dp));
  16. dp[0][0] = 1;
  17. for(int i = 1; i <= 20; i++)
  18. {
  19. dp[i][0] = dp[i-1][0]*10-dp[i-1][1];
  20. dp[i][1] = dp[i-1][0]*1;
  21. dp[i][2] = dp[i-1][2]*10+dp[i-1][1];
  22. }
  23. }
  24.  
  25. int cal(LL n)
  26. {
  27. int k = 0;
  28. memset(c,0,sizeof(c));
  29. while(n)
  30. {
  31. c[++k] = n%10;
  32. n/=10;
  33. }
  34. c[k+1] = 0;
  35. return k;
  36. }
  37. void solve(int len, LL n)
  38. {
  39. int flag = 0;//标记是否出现过49
  40. LL ans = 0;
  41. for(int i = len; i >= 1; i--)
  42. {
  43. ans+=c[i]*dp[i-1][2];
  44. if(flag)
  45. {
  46. ans+=c[i]*dp[i-1][0];
  47. }
  48. else if(c[i] > 4)
  49. {
  50. //这一位前面没有挨着49。但c[i]比4大,那么当这一位填4的时候,要加上dp[i-1][1]
  51. ans+=dp[i-1][1];
  52. }
  53. if(c[i+1]==4 && c[i]==9)
  54. {
  55. flag = 1;
  56. }
  57. }
  58. printf("%I64d\n",ans);
  59. }
  60. int main()
  61. {
  62. int t;
  63. LL n;
  64. init();
  65. scanf("%d",&t);
  66. while(t--)
  67. {
  68. scanf("%I64d",&n);
  69. int len = cal(n+1);
  70. solve(len, n);
  71. }
  72. return 0;
  73. }

DFS版

代码例如以下:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. #define LL __int64
  7. LL n, dp[25][3];
  8. //dp[i][j]:长度为i。状态为j
  9. int digit[25];
  10. //nstatus: 0:不含49, 1:不含49但末尾是4, 2 :含49
  11. LL DFS(int pos, int status, int limit)
  12. {
  13. if(pos <= 0) // 假设到了已经枚举了最后一位。而且在枚举的过程中有49序列出现
  14. return status==2;//注意是 ==
  15. if(!limit && dp[pos][status]!=-1) //对于有限制的询问我们是不可以记忆化的
  16. return dp[pos][status];
  17. LL ans = 0;
  18. int End = limit?digit[pos]:9; // 确定这一位的上限是多少
  19. for(int i = 0; i <= End; i++) // 每一位有这么多的选择
  20. {
  21. int nstatus = status; // 有点else s = statu 的意思
  22.  
  23. if(status==0 && i==4)//高位不含49。而且末尾不是4 ,如今末尾添4返回1状态
  24. nstatus = 1;
  25. else if(status==1 && i!=4 && i!=9)//高位不含49。且末尾是4,如今末尾加入的不是4返回0状态
  26. nstatus = 0;
  27. else if(status==1 && i==9)//高位不含49,且末尾是4,如今末尾加入9返回2状态
  28. nstatus = 2;
  29. ans+=DFS(pos-1, nstatus, limit && i==End);
  30. }
  31. if(!limit)
  32. dp[pos][status]=ans;
  33. return ans;
  34. }
  35.  
  36. int cal(LL x)
  37. {
  38. int cnt = 0;
  39. while(x)
  40. {
  41. digit[++cnt] = x%10;
  42. x/=10;
  43. }
  44. digit[cnt+1] = 0;
  45. return cnt;
  46. }
  47.  
  48. int main()
  49. {
  50. int t;
  51. scanf("%d",&t);
  52. while(t--)
  53. {
  54. memset(dp,-1,sizeof(dp));
  55. scanf("%I64d",&n);
  56. int len = cal(n);
  57. LL ans = DFS(len, 0, 1);
  58. printf("%I64d\n",ans);
  59. }
  60. return 0;
  61. }

HDU 3555 Bomb(数位DP模板啊两种形式)的更多相关文章

  1. HDU 3555 Bomb 数位dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others) Mem ...

  2. HDU 3555 Bomb 数位DP 入门

    给出n,问所有[0,n]区间内的数中,不含有49的数的个数 数位dp,记忆化搜索 dfs(int pos,bool pre,bool flag,bool e) pos:当前要枚举的位置 pre:当前要 ...

  3. HDU - 3555 - Bomb(数位DP)

    链接: https://vjudge.net/problem/HDU-3555 题意: The counter-terrorists found a time bomb in the dust. Bu ...

  4. Bomb HDU - 3555 (数位DP)

    Bomb HDU - 3555 (数位DP) The counter-terrorists found a time bomb in the dust. But this time the terro ...

  5. HDU 3555 Bomb (数位DP-记忆化搜索模板)

    题意 求区间[1,n]内含有相邻49的数. 思路 比较简单的按位DP思路.这是第一次学习记忆化搜索式的数位DP,确实比递推形式的更好理解呐,而且也更通用~可以一般化: [数位DP模板总结] int d ...

  6. HDU(3555),数位DP

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others ...

  7. hud 3555 Bomb 数位dp

    Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others) Total Subm ...

  8. HDU 2089 数位dp/字符串处理 两种方法

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  9. hdoj 3555 BOMB(数位dp)

    //hdoj 3555 //2013-06-27-16.53 #include <stdio.h> #include <string.h> __int64 dp[21][3], ...

随机推荐

  1. MySQL常用技能篇

    写在之前的话: 之前一直在用MSSERVER,刚用MySQL时有很多的不适应.就此小结一下工作中遇到的问题和场景(用的不是很深入,供初学者参考),文中出现的局限性欢迎指出 MySQL有客户端式(SQL ...

  2. 【BZOJ4444】国旗计划 - 决策单调性

    Description A国正在开展一项伟大的计划——国旗计划.这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈.这项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了N名优秀的边 ...

  3. C++ vector基本用法

    转自金河http://www.cnblogs.com/wang7/archive/2012/04/27/2474138.html 1 基本操作 (1)头文件#include<vector> ...

  4. Beat &#39;Em Up Game Starter Kit (横版格斗游戏) cocos2d-x游戏源代码

    浓缩精华.专注战斗! 游戏的本质是什么?界面?养成?NoNo!    游戏来源于对实战和比赛的模拟,所以它的本源就是对抗.就是战斗! 是挥洒热血的一种方式! 一个游戏最复杂最难做的是什么?UI?商城? ...

  5. python json及mysql——读取json文件存sql、数据库日期类型转换、终端操纵mysql及python codecs读取大文件问题

    preface: 近期帮师兄处理json文件,须要读到数据库里面,以备其兴许从数据库读取数据.数据是关于yelp站点里面的: https://github.com/Yelp/dataset-examp ...

  6. mysql-计算字段

    一.计算字段 存储在数据库表中的数据一般不是应用程序所需要的格式 1.如果想在一个字段中既显示公司名,又显示公司的地址,但这两个信息一般包含在不同的字段中. 2.城市.州和邮编存储在不同的列中,但邮件 ...

  7. 去除ListView 上下边界蓝色或黄色阴影

    默认的情况下,在 ListView 滑动到顶部或者是底部的时候,会有黄色或者蓝色的阴影出现.在不同的版本号上解决办法是不同的,在 2.3 版本号之前能够在 ListView 的属性中通过设置 andr ...

  8. 【转】webshell检测——使用auditd进行system调用审计

    本文档将介绍:如何通过Linux审计系统auditd监测WebShell执行系统命令的行为. 测试环境:CentOS7.0_x64 auditd简介 Linux审计系统提供了一种跟踪系统上与安全相关的 ...

  9. hdoj--1301--Jungle Roads(克鲁斯卡尔)

    Jungle Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tot ...

  10. Mvc前后端显示不同的404错误页

    最近做的系统前端是移动端的,后端是PC端,然后404页面不能用通一个,so  查找了一些资料,找到了一个解决办法 在Global.asax文件夹下添加Application_EndRequest事件处 ...