HDU 3555 Bomb + HDU 2089 不要62 数位dp入门题目

来源:互联网 发布:天津统计局人口数据 编辑:程序博客网 时间:2024/05/22 09:50

第一次接触数位dp的问题,在这里记录一下我个人的学习思路,如果能够对大家有什么帮助那就是最好的了。

动态规划也是刚刚开始学习,说实话对这种类型的题目现在还没有太适应。。。

数位dp通常都是类似这种叙述的问题:给定区间[l , m],求解其中满足(不满足)条件 p 的解集大小。

初始化的时候会开一个数组dp[n][10],dp[i][j] 表示第 i 位上为数字 j 并且符合(不符合)条件 p 的数目。一般用一个三重循环来搞定初始化的数值:

(pseudo code is as follow)

dp[0][0] = 1;for (int i = 1; i < n; i++){for (int j = 0; j < 10; j++){for (int k = 0; k < 10; k++){if (p){dp[i][j] += dp[i - 1][k];}}}}

第一重循环是n - 1位数位完全遍历,第二重和第三重循环分别是第 i 位和第 i - 1 位数位上0~9的数值。

dp[i][j] = dp[i][j] + dp[i - 1][k] 的含义是,当前位解集的大小为满足当前条件的数目和上一位解集大小之和(将这个过程联想成一棵树形的迭代结构)。接下来的过程就是根据题目具体描述来进行分析了。

HDU-2089 不要62 问题概述:给定数值范围n,m;求其中不是不吉利的数有多少个(不含4并且不含62)

AC代码如下

#include<iostream>using namespace std;//#include<cmath>//#include<string>long long dp[10][10];void init(){dp[0][0] = 1;for (int i = 1; i < 10; i++){for (int j = 0; j < 10; j++){for (int k = 0; k < 10; k++){if (j != 4 && !(j == 6 && k == 2)){dp[i][j] += dp[i - 1][k];}}}}}long long solution(long long n){int digit[15];int len = 0;long long mem = n, ans = 0;while (n > 0){digit[++len] = n % 10;n /= 10;}digit[len + 1] = 0;for (int i = len; i > 0; i--){for (int j = 0; j < digit[i]; j++){if (!(digit[i+1] == 6 && j == 2) && j != 4){ans += dp[i][j];}}if ((digit[i] == 2 && digit[i + 1] == 6) || digit[i] == 4){break;}}return ans;}int main(){init();long long n, m;while (cin >> n >> m){if (n == 0 && m == 0){break;}cout << solution(m + 1) - solution(n)<< endl;}//system("pause");return 0;}

相邻两位进行判断即可

HDU-3555 Bomb 问题概述:输入最大倒计时数n,求炸弹能量增加的最大值(求小于n并且含49的数字有多少个)

#include<iostream>using namespace std;//#include<cmath>//#include<string>long long dp[20][10];void init(){dp[0][0] = 1;for (int i = 1; i < 20; i++){for (int j = 0; j < 10; j++){for (int k = 0; k < 10; k++){if (!(j == 4 && k == 9)){dp[i][j] += dp[i - 1][k];}}}}}long long solution(long long n){int digit[20];int len = 0;long long mem = n, ans = 0;while (n > 0){digit[++len] = n % 10;n /= 10;}digit[len + 1] = 0;for (int i = len; i > 0; i--){for (int j = 0; j < digit[i]; j++){if (!(digit[i+1] == 4 && j == 9)){ans += dp[i][j];}}if ((digit[i] == 9 && digit[i + 1] == 4)){break;}}return mem - ans;}int main(){init();int t;long long n;cin >> t;while (t --){cin >> n;cout << solution(n + 1) << endl;}//system("pause");return 0;}
整体和2089的思路一样,换了个判断条件而已。


原创粉丝点击