入门...还在学习中,先贴一发大牛博客

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

题目大意:

  给一个数字n,范围在1~2^63-1,求1~n之间含有49的数字有多少个。

思路:

  经典的数位DP,学习了一下,看的别人的代码:http://www.cnblogs.com/luyi0619/archive/2011/04/29/2033117.html

  状态转移:

  dp[i][0]代表长度为 i 并且不含有49的数字的个数;

  dp[i][1]代表长度为 i 并且不含有49,但是最高位是9的数字的个数;

  dp[i][2]代表长度为 i 并且含有49的数字的个数。

  数组 a[i] 从低位到高位存储 n 的每一位数字。

  则:dp[i][0] = dp[i-1][0] * a[i] - dp[i-1][1];  表示长度为 i 的不含有49的数字的个数等于长度为 i - 1 的不含有49的数字的个数*当前的数字,因为这个位置可以填0~a[i] - 1,然后再减去长度为 i - 1 的最高位是9的数字的个数,因为如果长度为 i - 1 的最高位是9的话,那么高一位就不能填4了,否则就组成了49。

    dp[i][1] = dp[i-1][0]; 表示长度为 i 的并且不含有49同时最高位是9的数字的个数等于,长度为 i - 1 的不含有49的数字的个数,因为只要在它的高一位加上一个9就可以了。

    dp[i][2] = dp[i-1][2] * a[i] + dp[i-1][1]; 表示长度为 i 的含有49的数字的个数等于,长度为 i - 1 的数字的个数*当前的数字,再加上长度为 i - 1 的并且不含有49同时最高位是9的数字的个数,因为这个时候,只要在高一位加上一个4就可以了,这样在最高的两位就组成了一个49。

  做法是从数字的高位向低位扫描,对于第 i 位,

  1.   首先加上长度为 i - 1 的符合条件的数字个数;
  2.   再讨论以前是不是出现过49,如果出现过,就要再追加上长度为 i - 1 的不符合条件的数字的个数,因为以前已经有49了;
  3.   如果没有出现过,就要判断这一位是不是大于4呢,如果大于4,就要再追加上长度为 i - 1 的不含有49但是最高位是9的数字的个数,因为这个时候可以再这一位填4,因为它大于4嘛~;
  4.   然后就是判断一下,当前位和上一位是不是满足49,如果满足,标记出现了49了!为以后的判断做准备。

  其实这个题目还有一个地方不懂,就是为什么要在输入 n 后,要把 n 加1。想了一下特例,比如输入49,按照上面的做法,在第3步,并不会把符合条件的数字加上,因为4不是严格大于4,最后的执行结果就是0,但是如果加上1之后,n就变成了50,这样第3步恰好可以执行,结果就是正确的了。但是对于一般的情况,还是不知道为什么要把n加1……o(╯□╰)o

  这题还是卡了很久,照着别人的代码敲的,死活过不了,然后又找了一份代码:http://blog.csdn.net/acm_cxlove/article/details/7819907 才发现输入输出要用%I64d,这不是坑么……原来hdu要用%I64d,囧……

  所以,有时候的bug不是算法或者代码有错误,看看你的输入输出吧!还有,类似的情况,比如,输入文件写错了……更悲剧了。。

#include <cstdio>
#include <stack>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL; LL dp[25][3];
LL a[25];
unsigned long long n; void init()
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<21;i++)
{
dp[i][0]=dp[i-1][0]*10-dp[i-1][1];
dp[i][1]=dp[i-1][0];
dp[i][2]=dp[i-1][2]*10+dp[i-1][1];
}
} int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%I64d",&n);
n++;
int len=0;
memset(a,0,sizeof(a));
while(n)
{
a[++len]=n%10;
n/=10;
}
LL ans=0;
int last=0;
bool flag=false; for(int i=len;i>=1;--i)
{
ans+=dp[i-1][2]*a[i];//首先加上长度为 i - 1 的符合条件的数字个数;
if(flag) //以前是不是出现过49,如果出现过,就要再追加上长度为 i - 1 的不符合条件的数字的个数,因为以前已经有49了;
ans+=dp[i-1][0]*a[i];
if(!flag&&a[i]>4) //如果没有出现过,就要判断这一位是不是大于4呢,如果大于4,就要再追加上长度为 i - 1 的不含有49但是最高位是9的数字的个数,因为这个时候可以再这一位填4,因为它大于4嘛~;
ans+=dp[i-1][1];
if(last==4&&a[i]==9) //然后就是判断一下,当前位和上一位是不是满足49,如果满足,标记出现了49了!为以后的判断做准备。
flag=true;
last=a[i];
}
printf("%I64d\n",ans);
}
return 0;
}

HDU3555【数位DP】的更多相关文章

  1. hdu3555 数位dp

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

  2. hdu3555数位dp基础

    /* dp[i][0|1|2]:没有49的个数|最高位是9,没有49的个数|有49的个数 dp[i][0]=10*dp[i-1][0]-dp[i-1][1] dp[i][1]=dp[i-1][0] d ...

  3. hdu3555(数位DP dfs/递推)

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

  4. 数位dp浅谈(hdu3555)

    数位dp简介: 数位dp常用于求区间内某些特殊(常关于数字各个数位上的值)数字(比如要求数字含62,49): 常用解法: 数位dp常用记忆化搜索或递推来实现: 由于记忆化搜索比较好写再加上博主比较蒟, ...

  5. hdu3555 Bomb (记忆化搜索 数位DP)

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

  6. hdu---(3555)Bomb(数位dp(入门))

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

  7. hdu3555 Bomb 数位DP入门

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 简单的数位DP入门题目 思路和hdu2089基本一样 直接贴代码了,代码里有详细的注释 代码: ...

  8. 【Hdu3555】 Bomb(数位DP)

    Description 题意就是找0到N有多少个数中含有49. \(1\leq N \leq2^{63}-1\) Solution 数位DP,与hdu3652类似 \(F[i][state]\)表示位 ...

  9. 【hdu3555】Bomb 数位dp

    题目描述 求 1~N 内包含数位串 “49” 的数的个数. 输入 The first line of input consists of an integer T (1 <= T <= 1 ...

  10. [Hdu3555] Bomb(数位DP)

    Description 题意就是找0到N有多少个数中含有49. \(1\leq N \leq2^{63}-1\) Solution 数位DP,与hdu3652类似 \(F[i][state]\)表示位 ...

随机推荐

  1. Python中十六进制和字符串的转换(转载)

    调用Python内置int()函数把该字串转为数字.以下为在Python解释器编程环境下的操作示范: 把十六进制的字串转为十进制数字:Python代码>>> print int('f ...

  2. 【windows phone】CollectionViewSource的妙用

    在windows phone中绑定集合数据的时候,有时候需要分层数据,通常需要以主从试图形式显示.通常的方法是将第二个ListBox(主视图)的数据源绑定到第一个ListBox (从视图)的Selec ...

  3. 【BZOJ4561】[JLoi2016]圆的异或并 扫描线

    [BZOJ4561][JLoi2016]圆的异或并 Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面积并.异或面积并为:当一 ...

  4. Java之运行时异常与编译时异常区别

    Java中用2种方法处理异常: 1.在发生异常的地方直接处理: 2.将异常抛给调用者,让调用者处理. Java异常可分为3种: (1)编译时异常:Java.lang.Exception (2)运行期异 ...

  5. Hadoop实战-MapReduce之倒排索引(八)

    倒排索引 (就是key和Value对调的显示结果) 一.需求:下面是用户播放音乐记录,统计歌曲被哪些用户播放过 tom        LittleApple jack       YesterdayO ...

  6. 超实用的 Nginx 极简教程,覆盖了常用场景(转)

    概述 安装与使用 安装 使用 nginx 配置实战 http 反向代理配置 负载均衡配置 网站有多个 webapp 的配置 https 反向代理配置 静态站点配置 搭建文件服务器 跨域解决方案 参考 ...

  7. sqlserver锁表查看

    sp_lock--查询哪个进程锁表了,spid:进程ID,ObjId:对象ID EXEC sp_executesql N'KILL [spid]'--杀进程 select object_name([O ...

  8. ModuleNotFoundError: No module named 'numpy.core._multiarray_umath' ImportError: numpy.core.multiarray failed to import

      出现以下错误:可能是因为你的numpy版本太低 更新numpy的版本 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgra ...

  9. shell动态变量

    面对变量中嵌套变量,可以这么做 other_devops_ip="......." options='_ip' tennat_name='other_devops' tennat_ ...

  10. .PHP生成静态html文件的方法

    1. [代码][PHP]代码     1,下面使用模版的一个方法!   <?php $fp = fopen ("templets.html","a");  ...