数位DP——Bomb ( HDU 3555 )
2016-07-18 17:06
281 查看
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3555
分析:
题意为给除一个数N,求出1-N这些数中含有49的子串的数的个数。初学数位DP,这道题就当例题了。
题解:
首先我们确定状态转移方程
dp[i][j]用于存储符合条件的数的个数
i 代表目前处理的数长度为i
这里dp[i][j]处理的数可以包含前导0
dp[i][0]代表长度为i的数中不含49的数量
dp[i][1]代表长度为i的数中不含49但是最高位为9的数的数量
dp[i][2]代表长度为i的数中包含49的数的数量
代码:
处理:
对于一个数字n,我们假设它的长度为len,并且第i位储存在a[i]中。
首先加上a[i]*剩下i-1位中满足条件的数的个数。
如果高位已经出现过49,加上a[i]*剩下i-1位中不满足条件的数的个数。
如果高位未出现49,且第i位>4,第i-1位为9,则加上剩下i-1位中以9开头的数的个数。
判断高一位和本位是否构成49,更新标志。
代码:
注意:
我们在输入n后,需要对n进行+1的操作,因为我们上述操作是统计[1,n)区间内符合条件的数的个数,并没有统计n的情况,n+1是为了不再特殊处理n
我们在获取n的每一位数字时,应该预先多处理一位,令a[len+1]=0,这样做是为了不特殊处理n<10的情况
AC代码:
http://acm.hdu.edu.cn/showproblem.php?pid=3555
分析:
题意为给除一个数N,求出1-N这些数中含有49的子串的数的个数。初学数位DP,这道题就当例题了。
题解:
首先我们确定状态转移方程
dp[i][j]用于存储符合条件的数的个数
i 代表目前处理的数长度为i
这里dp[i][j]处理的数可以包含前导0
dp[i][0]代表长度为i的数中不含49的数量
dp[i][1]代表长度为i的数中不含49但是最高位为9的数的数量
dp[i][2]代表长度为i的数中包含49的数的数量
代码:
dp[0][0] = 1; for(int i=1; i<=20; 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-2][2]*10+dp[i-1][1]; }
处理:
对于一个数字n,我们假设它的长度为len,并且第i位储存在a[i]中。
首先加上a[i]*剩下i-1位中满足条件的数的个数。
如果高位已经出现过49,加上a[i]*剩下i-1位中不满足条件的数的个数。
如果高位未出现49,且第i位>4,第i-1位为9,则加上剩下i-1位中以9开头的数的个数。
判断高一位和本位是否构成49,更新标志。
代码:
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=true; }
注意:
我们在输入n后,需要对n进行+1的操作,因为我们上述操作是统计[1,n)区间内符合条件的数的个数,并没有统计n的情况,n+1是为了不再特殊处理n
我们在获取n的每一位数字时,应该预先多处理一位,令a[len+1]=0,这样做是为了不特殊处理n<10的情况
AC代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define __int64 long long __int64 dp[25][3]; void Init() { memset(dp,0,sizeof(dp)); dp[0][0] = 1; int i; for(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]; } } __int64 solve(__int64 n) { __int64 i,len = 0,a[25],flag = 0,ans = 0; while(n) { a[++len] = n%10; n/=10; } a[len+1] = 0; for(i = len;i;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; __int64 n; scanf("%d",&t); Init(); while(t--) { scanf("%I64d",&n); printf("%I64d\n",solve(n+1)); } return 0; }
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法