hdu5179 数位dp
2016-07-25 16:20
471 查看
题目链接:点击打开链接
题意:
有一种称为“美丽数”,定义为 a[i] % a[j] == 0 (1 <= i <= n, i > j);
a[i] 表示第 i 位数字,n 是这个数的位数;
如:931, 9993, 1111 便是美丽数;
而 932, 5421 等是不符合的;
求区间 [L, R] 之间有多少这样的数;
理解:
很容易想到数位dp;
但是又有些要注意的地方;
特别是前导位为 0 的情况;
递推式含义:dp[i][j] 表示以 j 位开头的 i 位数的符合条件的个数;
即:dp[i][j] += dp[i - 1][k];
初始值是重点,得根据题意给出;
此处的初始值应为:dp[1][1 ~ 9] = 1;
即:在一位数的情况下,除零以外的其他数字都是美丽数;
然后还要得到一个值;
就是要把在前导位为 0 的情况下的值算出来;
即:dp[i][0] += dp[i - 1][j] (1 <= j <= 9);
因为在从高位算到低位时,只能求出在当前位数下的数小于当前数的情况;
不能算出前导位为 0 的美丽数;
具体看代码分析;
需注意的是,代码中的前导位 0 是算作一位数字的;
即:0111 是 4 位数,因此 dp[4][0] 求出的是所有三位数的美丽数的个数之和;
代码如下:
题意:
有一种称为“美丽数”,定义为 a[i] % a[j] == 0 (1 <= i <= n, i > j);
a[i] 表示第 i 位数字,n 是这个数的位数;
如:931, 9993, 1111 便是美丽数;
而 932, 5421 等是不符合的;
求区间 [L, R] 之间有多少这样的数;
理解:
很容易想到数位dp;
但是又有些要注意的地方;
特别是前导位为 0 的情况;
递推式含义:dp[i][j] 表示以 j 位开头的 i 位数的符合条件的个数;
即:dp[i][j] += dp[i - 1][k];
初始值是重点,得根据题意给出;
此处的初始值应为:dp[1][1 ~ 9] = 1;
即:在一位数的情况下,除零以外的其他数字都是美丽数;
然后还要得到一个值;
就是要把在前导位为 0 的情况下的值算出来;
即:dp[i][0] += dp[i - 1][j] (1 <= j <= 9);
因为在从高位算到低位时,只能求出在当前位数下的数小于当前数的情况;
不能算出前导位为 0 的美丽数;
具体看代码分析;
需注意的是,代码中的前导位 0 是算作一位数字的;
即:0111 是 4 位数,因此 dp[4][0] 求出的是所有三位数的美丽数的个数之和;
代码如下:
#include <cstdio> #include <cstring> #include <cmath> #include <ctime> #include <iostream> #include <algorithm> #include <vector> #include <string> #include <map> #include <set> #include <queue> #include <stack> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MIN_INF = 1e-7; const int MAX_INF = (1e9) + 7; #define X first #define Y second int dp[15][15]; void init() { for (int i = 1; i < 10; ++i) { //初始值 dp[1][i] = 1; dp[2][0] += 1; } for (int i = 2; i < 12; ++i) { for (int j = 1; j < 10; ++j) { for (int k = 1; k < 10; ++k) { if (j >= k && (j % k == 0)) { dp[i][j] += dp[i - 1][k]; } } dp[i + 1][0] += dp[i][j]; //计算前导位为 0 的美丽数的和 } } } int solve(int n) { vector<int> di; while (n) { //分解数 di.push_back(n % 10); n /= 10; } di.push_back(0); //加上前导零 int ans = 0; for (int i = 2; i < di.size(); ++i) { //求出小于等于 n 的位数的前导位为 0 的美丽数的和 ans += dp[i][0]; } for (int i = di.size() - 2; i >= 0; --i) { for (int j = 1; j < di[i]; ++j) { if (di[i + 1] % j == 0) { //符合条件 ans += dp[i + 1][j]; } } if (di[i] == 0 || di[i + 1] % di[i] != 0) { //如果不符合该条件,那么后面以这个为前导数的数就一定不是美丽数 break; } } return ans; } int main() { init(); int t; cin >> t; while (t--) { int L, R; cin >> L >> R; cout << solve(R + 1) - solve(L) << endl; } return 0; }
相关文章推荐
- 详解Android应用中屏幕尺寸的获取及dp和px值的转换
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- LFC1.0.0 版本发布
- Android dpi,dip,dp的概念以及屏幕适配
- Android px、dp、sp之间相互转换
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- android中像素单位dp、px、pt、sp的比较
- Android对px和dip进行尺寸转换的方法
- Android根据分辨率进行单位转换-(dp,sp转像素px)
- android 尺寸 dp,sp,px,dip,pt详解
- DP问题各种模型的状态转移方程
- POJ-1695-Magazine Delivery-dp
- nyoj-1216-整理图书-dp
- TYVJ1193 括号序列解题报告
- 对DP的一点感想
- TYVJ上一些DP的解题报告
- soj1005. Roll Playing Games
- 01背包问题