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

题目大意:求 \([1,n]\) 范围内有多少数包含“49”。

解题思路:

这个问题我们可以分两种解法来考虑:第一种是求不包含“49”的数的数量,用后减一下;另一种就是直接求包含“49”的数的数量。

解法1:求多少数不包含“49”

这种方法我们先通过数位DP求出 \([0,n]\) 区间范围内有多少数不包含“49”(假设数量为 \(x\) ),然后可以得到答案为 \(n+1-x\) 。

我们可以设计一个函数 dfs(int pos, int stat, bool limit) 来返回区间 \([0,n]\) 范围内有多少数不包含“49”,其中:

  • pos 表示当前所处数位;
  • stat 表示前一位的数是不是‘4’(如果前一位是‘4’当前位是‘9’则凑成“49”);
  • limit 用于标记当前是否受限制(true:受限制;false:不受限制)。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
long long f[66][2], n;
int T, a[66];
void init() {
memset(f, -1, sizeof(f));
}
long long dfs(int pos, int stat, bool limit) {
if (pos < 0) return 1;
if (!limit && f[pos][stat] != -1) return f[pos][stat];
int up = limit ? a[pos] : 9;
long long tmp = 0;
for (int i = 0; i <= up; i ++) {
if (stat && i == 9) continue;
tmp += dfs(pos-1, i==4, limit && i == up);
}
if (!limit) f[pos][stat] = tmp;
return tmp;
}
long long get_num(long long x) {
int pos = 0;
while (x) {
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos-1, 0, true);
}
int main() {
init();
scanf("%d", &T);
while (T --) {
scanf("%lld", &n);
printf("%lld\n", n+1-get_num(n));
}
return 0;
}

解法2:求多少数包含“49”

相对解法1是间接的方式进行求解。我们现在这种方式则是 直接 求解 \([0,n]\) 范围内有多少个数包含“49”。

我们可以设计一个函数 dfs(int pos, int stat, bool limit) 来返回区间 \([0,n]\) 范围内有多少数不包含“49”,其中:

  • pos 表示当前所处数位;
  • stat 表示前一位的数是不是‘4’(如果前一位是‘4’当前位是‘9’则凑成“49”);
  • limit 用于标记当前是否受限制(true:受限制;false:不受限制)。

虽然是一样的,但是在处理的时候统计结果的方式却不一样。

这里特别需要注意的是限制条件和非限制条件下不同的处理。

假设我们现在要找的是区间 \([0,n]\) 范围内有多少数包含“49” 遍历到 pos 位并且 pos+1 位是‘4’, pos 位是‘9’,则我们可以得知:

  1. 如果当前处于限制状态下,则之后有 \(n \% 10^{pos} + 1\) 个数满足条件;
  2. 如果当前处于非限制状态下,则之后有 \(10^{pos}\) 个数满足条件。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
long long f[66][2], n;
int T, a[66];
void init() {
memset(f, -1, sizeof(f));
}
long long pow10(int a) {
if (a == 0) return 1;
if (a == 1) return 10;
long long t = pow10(a/2);
return t * t * (a%2 ? 10 : 1);
}
long long dfs(int pos, int stat, bool limit) {
if (pos < 0) return 0; // 返回0说明没找到包含49的
if (!limit && f[pos][stat] != -1) return f[pos][stat];
int up = limit ? a[pos] : 9;
long long tmp = 0;
for (int i = 0; i <= up; i ++) {
if (stat && i == 9) { // 说明接下来pos位的10的pos次方个数都满足条件
// tmp += pow10(pos); // 直接这么写是错的,此时也要考虑边界条件限制
// 修正如下
if (limit) tmp += n % pow10(pos) + 1;
else tmp += pow10(pos);
}
else tmp += dfs(pos-1, i==4, limit && i == up);
}
if (!limit) f[pos][stat] = tmp;
return tmp;
}
long long get_num(long long x) {
int pos = 0;
while (x) {
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos-1, 0, true);
}
int main() {
init();
scanf("%d", &T);
while (T --) {
scanf("%lld", &n);
printf("%lld\n", get_num(n));
}
return 0;
}

HDU3555 Bomb 题解 数位DP的更多相关文章

  1. [Hdu3555] Bomb(数位DP)

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

  2. 【Hdu3555】 Bomb(数位DP)

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

  3. HDU 3555 Bomb(数位DP)

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

  4. HDU 3555 Bomb(数位DP模板啊两种形式)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 Problem Description The counter-terrorists found ...

  5. 动态规划晋级——HDU 3555 Bomb【数位DP详解】

    转载请注明出处:http://blog.csdn.net/a1dark 分析:初学数位DP完全搞不懂.很多时候都是自己花大量时间去找规律.记得上次网络赛有道数位DP.硬是找规律给A了.那时候完全不知数 ...

  6. POJ-2282题解&数位DP总结

    一.题意 给定一个区间[a, b](注意输入的时候可能a > b,所以,在数据输入后,要先比较a和b,如果a > b,交换a和b的值),统计这个区间里面,数位上有多少个0.多少个1.--. ...

  7. luogu2657-Windy数题解--数位DP

    题目链接 https://www.luogu.org/problemnew/show/P2657 分析 第一道数位DP题,发现有点意思 DP求\([L,R]\)区间内的XXX个数,很套路地想到前缀和, ...

  8. 洛谷P2602 [ZJOI2010]数字计数 题解 数位DP

    题目链接:https://www.luogu.com.cn/problem/P2602 题目大意: 计算区间 \([L,R]\) 范围内 \(0 \sim 9\) 各出现了多少次? 解题思路: 使用 ...

  9. 洛谷P3413 SAC#1 - 萌数 题解 数位DP

    题目链接:https://www.luogu.com.cn/problem/P3413 题目大意: 定义萌数指:满足"存在长度至少为2的回文子串"的数. 求区间 \([L,R]\) ...

随机推荐

  1. Libev源码分析04:Libev中的相对时间定时器

    Libev中的超时监视器ev_timer,就是简单的相对时间定时器,它会在给定的时间点触发超时事件,还可以在固定的时间间隔之后再次触发超时事件. 所谓的相对时间,指的是如果你注册了一个1小时的超时事件 ...

  2. hdu 1839 Delay Constrained Maximum Capacity Path(spfa+二分)

    Delay Constrained Maximum Capacity Path Time Limit: 10000/10000 MS (Java/Others)    Memory Limit: 65 ...

  3. LightOJ 1269 Consecutive Sum (Trie树)

    Jan's LightOJ :: Problem 1269 - Consecutive Sum 题意是,求给定序列的中,子序列最大最小的抑或和. 做法就是用一棵Trie树,记录数的每一位是0还是1.查 ...

  4. python命令之m参数 局域网传输

    在命令行中使用python时,python支持在其后面添加可选参数. python命令的可选参数有很多,例如:使用可选参数h可以查询python的帮助信息: 可选参数m 下面我们来说说python命令 ...

  5. tensorflow入门——3解决问题——4让我们开始吧

    深度学习适合解决海量数据和复杂问题 在机器学习中,语音识别,图像识别,语意识别用的是不同的技术,从事相关工作的人合作几乎不可能. 深度学习改变了这一切. 80年代计算机很慢,数据集很小,因此深度学习没 ...

  6. rowStyle设置Bootstrap Table行样式

    日常开发中我们通常会用到隔行变色来美化表格,也会根据每行的数据显示特定的背景颜色,如果库存低于100的行显示红色背景 CSS样式 <style> .bg-blue { background ...

  7. Windows Community Toolkit 3.0 新功能 在WinForms 和 WPF 使用 UWP 控件

    本文告诉大家一个令人震惊的消息,Windows Community Toolkit 有一个大更新,现在的版本是 3.0 .最大的提升就是 WinForm 和 WPF 程序可以使用部分 UWP 控件. ...

  8. 深入理解String、StringBuffer、StringBuilder(转)

    文章系转载,非原创,原地址: http://www.cnblogs.com/dolphin0520/p/3778589.html 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公 ...

  9. Linux创建用户、设置密码、修改用户、删除用户命令

    与大家分享下Linux系统中创建用户.设置密码.修改用户.删除用户的命令,希望对你有所帮助. useradd testuser  创建用户testuserpasswd testuser  给已创建的用 ...

  10. CSS 伸缩布局

    转载于:https://blog.csdn.net/weixin_41342585/article/details/80140513 1. flex-direction:设置伸缩容器中成员的排列方式 ...