HDU3555Bomb数位DP入门题
来源:互联网 发布:webapp登录界面源码 编辑:程序博客网 时间:2024/05/09 13:49
题意:求1~n的范围内含有49的数字的个数
思路一:
按照2089的思路,计算1~n的范围内不含有49的数字的个数。其中需要注意的一点是slove(n+1),是计算[0,n]内不含有49的数字的个数,特别要注意包含了0。就比如solve(50)计算出来的是50,其实这50的数是从0-50开始的不包含49的50个数。所以最后答案是n+1-solve(n+1)
#include<iostream>#include<cstdio>using namespace std;typedef long long LL;LL dp[30][30];LL a[30];void getdp(){ dp[0][0] = 1; for(LL i = 1; i < 25; i++) { for(LL j = 0; j < 10; j++) { if(j == 4) { for(LL k = 0; k < 10; k++) dp[i][j] += dp[i-1][k]; dp[i][j] -= dp[i-1][9]; } else { for(LL k = 0; k < 10; k++) dp[i][j] += dp[i-1][k]; } } }}LL slove(LL num){ a[0] = 0; while(num) { a[++a[0]] = num % 10; num /= 10; } a[a[0]+1] = 0; LL ans = 0; for(LL i = a[0]; i >= 1; i--) { for(LL j = 0; j < a[i]; j++) if(!(a[i+1] == 4 && j == 9)) ans += dp[i][j]; if(a[i+1] == 4 && a[i] == 9) break; } return ans;}int main(){ int T; LL n; getdp(); scanf("%d", &T); while(T--) { scanf("%I64d", &n); LL k1 = slove(n+1); printf("%I64d\n", n - (k1-1)); } return 0;}
来自http://www.cnblogs.com/liuxueyang/archive/2013/04/14/3020032.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 位,
- 首先加上长度为 i - 1 的符合条件的数字个数;
- 再讨论以前是不是出现过49,如果出现过,就要再追加上长度为 i - 1 的不符合条件的数字的个数,因为以前已经有49了;
- 如果没有出现过,就要判断这一位是不是大于4呢,如果大于4,就要再追加上长度为 i - 1 的不含有49但是最高位是9的数字的个数,因为这个时候可以再这一位填4,因为它大于4嘛~;至于为什么不是等于是4,还是前面一篇文章中说的,枚举只是枚举到小于该位的数,当枚举下一位时候如果该位本来就是4,那么4自然就会被固定住。
- 然后就是判断一下,当前位和上一位是不是满足49,如果满足,标记出现了49了!为以后的判断做准备。
#include<iostream>#include<cstring>#include<cstdio>using namespace std;long long dp[25][3];void Init(){ memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for(int i = 1; i <= 22; 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]; }}long long solve(long long n){ long long a[25], len = 0, ans = 0, flag = 0; while(n) { a[++len] = n % 10; n /= 10; } a[len+1] = 0; for(int i = len; i >= 1; i--) { ans += dp[i-1][2]*a[i]; if(flag) ans += dp[i-1][0]*a[i]; if(!flag && a[i] > 4) ans += dp[i-1][1]; if(a[i+1] == 4 && a[i] == 9) flag = 1; } return ans;}int main(){ int T; long long n; scanf("%d", &T); Init(); while(T--) { scanf("%I64d", &n); printf("%I64d\n", solve(n+1)); } return 0;}
- hdu3555Bomb【数位dp入门题】
- HDU3555Bomb数位DP入门题
- HDU3555Bomb数位DP入门题目
- hdu3555Bomb 数位dp
- hdu3555Bomb(记忆优化,数位dp)
- hdu3555Bomb(数位dp&&记忆化搜索)
- 数位DP入门题
- hdu3555 数位dp入门题
- HDU2089 数位DP入门题
- hdu 2089 数位dp入门题
- hdu 3555数位dp基础入门题
- hdu2089(数位dp入门题)
- hdu3555(数位dp入门题)
- hdu 3555数位DP 入门题
- hdu3555+cf55D 数位dp入门题
- HDU 2089 数位DP 入门题
- HDU 2089 数位DP入门题
- hdu2089 不要62--数位dp入门题
- TCP/IP学习(1)
- 将shape文件导入到postgis
- 法家
- listview实现点击选中
- 为什么我选择使用Spring
- HDU3555Bomb数位DP入门题
- cocos2dx Win32下添加控制台输出
- 迪菲-赫尔曼密钥交换
- [Codeforces Round #372 DIV1C (CF715C)] Digit Tree
- 动态绑定和多态——面向对象最核心的机制
- 2017 年 11 个移动 App 开发趋势
- Spring Boot 入门
- 世界
- Python运算符