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

题目链接: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. JS中小数如何转化为百分数并能四舍五入

    <script type="text/javascript">//n表示百分数保留的位数 function toPercent(n){ n = n || 2; retu ...

  2. 使用kbmmw 的调度事件动态显示时间

    kbmmw 里面提供了强大的事件调度功能,今天简单演示一个使用调度事件在窗体上显示时间. 建立一个新工程. 放上几个控件 在窗体里面引用单元 kbmMWScheduler, 然后添加过程 unit U ...

  3. GitLab Pages expect to run on their own virtual host

    GitLab Pages administration | GitLab https://docs.gitlab.com/ce/administration/pages/

  4. Node中的Socket.IO 简单Demo及说明

    注:下面Demo的Server和Client都是纯后端. 并没有web页面. Server端代码: var express = require('express'); var app = expres ...

  5. linux下配置yum源

    备份原yum源   /etc/yum.repos.d/centos一base.repo 下载yum源       wagt 源网址/源名称/etc/yum.repos.d/原yum名

  6. 人生苦短之Python类的一二三

    在Python中,类也是以class开头定义的.我们定义一个动物类,它有名字和年龄,在java变量有实例变量和局部变量,方法内的变量是局部变量,类里面的变量是实例变量.那么在Python中的类及其属性 ...

  7. RobotFramework教程使用笔记——Selenium2Library库

    selenium之前已经学习介绍过了,它是一个支持多语言.多平台.多浏览器的web自动化测试框架,在robotframework中也可以导入selenium库来进行web自动化测试.它使用seleni ...

  8. 如何刷新本地的DNS缓存?

    为了提高网站的访问速度,系统会在成功访问某网站后将该网站的域名.IP地址信息缓存到本地.下次访问该域名时直接通过IP进行访问.一些网站的域名没有变化,但IP地址发生变化,有可能因本地的DNS缓存没有刷 ...

  9. double转int时精度不一致问题

    float和double类型的主要设计目的是为了科学计算和工程计算.它们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该 ...

  10. 1、VGG16 2、VGG19 3、ResNet50 4、Inception V3 5、Xception介绍——迁移学习

    ResNet, AlexNet, VGG, Inception: 理解各种各样的CNN架构 本文翻译自ResNet, AlexNet, VGG, Inception: Understanding va ...