hdu3555 Bomb (秒懂的数位dp)
来源:互联网 发布:福州天趣网络 编辑:程序博客网 时间:2024/06/07 13:39
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
3
1
50
500
Sample Output
0
1
15
Hint
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”,
so the answer is 15.
题意:
就是找从0到n的数中含有49的数字个数,4和9必须相邻。
解题思路:
1.先说一下数位dp,数位,就是数字的个,十,百,千位,etc。在数位上dp,在很多人看完数位dp后会说这不是个记忆化搜索吗?其实dp就是由记忆化变形过来的,俩者的复杂度几近相同。这个观点可以看“挑战程序设计”这本书验证。2.进入正题。 首先在数位上dp,我们就需要把这个数的每一位分解出来。具体看下面代码块。
int len = 0; //x为要分解的数,分解出来储存在a数组中。a是全局数组,大小定位你要分解的最大数的位数 while(x) { a[len++] = x % 10; x /= 10; }
分解出来,干什么呢?下面就要先看题目要求,拿本题来说,要找含有49的数字个数。但是直接找含有49的数字较为麻烦,那我 们可以找到不含49的数字个数,然后拿总数相减就可以得到答案。3.那现在任务变成求,不含49的数字个数。 先上个最简单的数位dp板子,帮助理解。
ll dfs(int pos,int pre,bool limit)//pos表示现在是数的第几位,pre是前一位数位上的数,limit是核心,一会儿细讲{ if(pos == -1) //应为数位数组a是从0开始存储,所以pos变为-1表示这个数每一位都遍历完了,就返回 1 return 1; //1表示搜索结束,找到一个合法数字 int up = limit?a[pos]:9; //核心:细讲 ll ans = 0; //统计合乎要求的数 for(int i = 0;i <= up;i++) //遍历当前数位上可能取的每一个数 { if(pre == 4 && i == 9) //当前一位是4,且当前位是9的我们就不往下遍历,最后含有49的自然就没计数 { continue; }else{ ans += dfs(pos-1,i,limit && i == a[pos]); //不含49,就往下遍历pos是从最大数位开始 } } return ans;}
4.limit这是个好东西,能想出来的人,我现在先Orz(膜拜)一下。 5752,比如给这个数,我们从最高位去遍历,那么最高位是千位,可以取的数字是0,1,2,3,4,5. 至于这里的前导零先不管。我们看一下取0~4和取5,有什么分别? 先闭上眼睛想想。 。 。 。 取0~4,,,那么百位,可以取哪几个数? 答案:0--9 . 取5呢,,,那么百位就只能取0--7.。。这里能想通吧。因为一个数是从0一直增大,但是不能超过所给的数字吧 那么来看代码。 int up = limit?a[pos]:9; 如果有限制,limit为真,那么我们遍历这个数位的上限up就是a[pos],a[pos]就是存储的当前最大位。就是千位的7. 如果没有限制,limit为假,那么up就是9. 。 那么我们关心的问题就是什么时候limit为真。对应于刚刚举得例子就是 千位取5,遍历百位的时候0--7. 百位取7,遍历十位的时候0--5. 也就是说遍历当前位的时候,如果前一位是最大的那个,那么limit为真。 。。 ans += dfs(pos-1,i,limit && i == a[pos]); 。 当往下遍历时,为什么限制limit的值是“limit && i == a[pos]”这个东西。 。 我们想i是从0遍历到上限。如果i==a[pos],那么就是说i==当前位最大的那个数。那么下一位是不是受限制了? 所以当相等且limit为真,下一位受限制。limit就为真。为什么要“limit && i == a[pos]”这个式子 要且上一个limit,limit表示当前位受前一位限制, 。。 我举个例子还是5752 .。 如果前位取4.limit为假,那么百位取到a[pos]也就是7的时候受限制吗???写几个数就懂了。5.下面说循环遍历的注意点。hdu有个不要62的题。 。 对于每一个题,我们根据要求改变条件,就可以得到不同的题目要求的答案。例如本题,我们要找不含49,那么 根据pre和当前位判断,如果含49,就跳过。如果是不要62,那么也是一样。自己思考。
AC代码:
# include <cstdio># include <cstring># define ll long longusing namespace std;ll dp[50][10];int a[50];ll dfs(int pos,int pre,bool limit){ if(pos == -1) return 1; if(!limit && dp[pos][pre] != -1) { return dp[pos][pre]; } int up = limit?a[pos]:9; ll ans = 0; for(int i = 0;i <= up;i++) { if(pre == 4 && i == 9) { continue; }else{ ans += dfs(pos-1,i,limit && i == a[pos]); } } if(!limit) { dp[pos][pre] = ans; } return ans;}ll solve(ll x){ int len = 0; while(x) { a[len++] = x % 10; x /= 10; } return dfs(len-1,0,1);}int main(){ int T; ll ri; scanf("%d",&T); memset(dp,-1,sizeof(dp)); while(T--) { scanf("%lld",&ri); printf("%lld\n",ri-solve(ri)+1); } return 0;}
贴了代码:才发现没说记忆化的问题。算啦,有时间再补,当然,如果有人需要,请留言。我看到后,马上补齐。敲了这么多,如果有帮助留言顶一下,点个赞。如果有叙述错误,也请指出,共同进步。
- hdu3555 Bomb (秒懂的数位dp)
- HDU3555 Bomb(数位dp)
- HDU3555 Bomb(数位dp)
- HDU3555 Bomb (数位dp)
- hdu3555 Bomb(数位dp)
- HDU3555 Bomb(数位DP)
- hdu3555 Bomb(数位dp)
- 【数位DP】 hdu3555 Bomb
- 【hdu3555】【数位DP】Bomb
- 【数位DP】Bomb HDU3555
- hdu3555 Bomb 数位DP
- HDU3555:Bomb(数位DP)
- hdu3555 Bomb (数位DP)
- HDU3555 Bomb 数位DP
- Hdu3555 - Bomb - 数位dp
- hdu3555 Bomb 数位dp
- hdu3555 Bomb(数位DP)
- HDU3555 Bomb 数位DP
- 通过文本文件统计页面访问量
- 不用晶振,STM32内部HSI时钟的倍频使用
- SpringMVC学习系列(10) 之 异常处理
- 数据结构-哈希表
- Genymotion安装问题汇总
- hdu3555 Bomb (秒懂的数位dp)
- 多控制点生成贝塞尔(Bezier-Curve)样条 C语言版
- Selenium 高阶应用之WebDriverWait 和 expected_conditions
- linux(ubuntu)和windows7双系统安装
- 二进制的转换与二进制的运算
- JAVA中super详解
- 数据库基础操作
- 编写windbg调试器扩展 入门篇1
- 光流法网址