数字游戏
[https://vjudge.net/problem/LibreOJ-10164]:
题目大意:
科协里最近很流行数字游戏。
某人命名了一种不降数,这种数字必须满足从左到右各位数字呈非下降关系,如 123,446。
现在大家决定玩一个游戏,指定一个整数闭区间 [a,b],问这个区间内有多少个不降数。
输入格式
输入包含多组测试数据。
每组数据占一行,包含两个整数 a 和 b。
输出格式
每行给出一组测试数据的答案,即 [a,b] 之间有多少不降数。
数据范围
1≤ a ≤ b ≤2^31−1
解题思路:
f[i][j] 数组代表着最高位是j并且一共有i位不降数的集合
f[i][j] = f[i-1][j] + f[i-1][j+1] + f[i-1][j+2] +…+ f[i-1][9];
按照数位DP分析步骤: 假设我们当前枚举到第i位,且第i位上的数字是x,那么现在对于答案的第i位数字j来说,可以填两类数字:
1.j 取0~x-1 那么res += f[i+1][j];
2.j 取 x last记录x,再枚举下一位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <bits/stdc++.h> using namespace std; const int N = 12; int a[N]; int f[N][N]; void init() { for (int i = 0; i <= 9; i++) { f[1][i] = 1; } for (int i = 2; i < N; i++) { for (int j = 0; j <= 9; j++) { for (int k = j; k <= 9; k++) { f[i][j] += f[i - 1][k]; } } } } int dp(int n) { if (n == 0) { return 1; } int cnt = 0; while (n) { a[++cnt] = n % 10; n /= 10; } int ans = 0; int last = 0; for (int i = cnt; i >= 1; i--) { int now = a[i]; for (int j = last; j < now; j++) { ans += f[i][j]; } if (now < last) { break; } last = now; if (i == 1) { ans++; } } return ans; } int main() { init(); int l, r; while (cin >> l >> r) { printf("%d\n", dp(r) - dp(l - 1)); } return 0; }
|
windy数
[https://www.luogu.com.cn/problem/P2657]:
题意:windy定义了一种windy数。
不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。
windy想知道,在A和B之间,包括A和B,总共有多少个windy数?
Input
包含两个整数,A,B。
满足1≤A≤B≤2000000000 .
Sample 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include <bits/stdc++.h> using namespace std; const int N = 12; int a[N]; int f[N][N]; void init() { for (int i = 0; i <= 9; i++) { f[1][i] = 1; } for (int i = 2; i < N; i++) { for (int j = 0; j <= 9; j++) { for (int k = 0; k <= 9; k++) { if (abs(j - k) >= 2) { f[i][j] += f[i - 1][k]; } } } } } int dp(int n) { if (n == 0) { return 0; } int cnt = 0; while (n) { a[++cnt] = n % 10; n /= 10; } int ans = 0; int last = -2; for (int i = cnt; i >= 1; i--) { int now = a[i]; for (int j = (i == cnt); j < now; j++) { if (abs(j - last) >= 2) { ans += f[i][j]; } } if (abs(now - last) < 2) { break; } last = now; if (i == 1) { ans++; } } for (int i = 1; i < cnt; i++) { for (int j = 1; j <= 9; j++) { ans += f[i][j]; } } return ans; } int main() { init(); int l, r; cin >> l >> r; printf("%d\n", dp(r) - dp(l - 1)); return 0; }
|
acwing1081:度的数量



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <bits/stdc++.h> using namespace std; const int N = 35; int a[N]; int f[N][N]; int k, b; void init() { for (int i = 0; i < N; i++) { f[i][0] = 1; } for (int i = 1; i < N; i++) { for (int j = 1; j <= i; j++) { f[i][j] += f[i - 1][j] + f[i - 1][j - 1]; } } } int dp(int n) { if (n == 0) { return 0; } int cnt = 0; while (n) { a[++cnt] = n % b; n /= b; } int ans = 0, last = 0; for (int i = cnt; i >= 1; i--) { int x = a[i]; if (x) { ans += f[i - 1][k - last]; if (x > 1) { if (k - (last + 1) >= 0) { ans += f[i - 1][k - (last + 1)]; break; } } else { last += 1; if (last > k) { break; } } } if (i == 1 && last == k) { ans++; } } return ans; } int main() { init(); int l, r; scanf("%d%d", &l, &r); scanf("%d", &k); scanf("%d", &b); printf("%d\n", dp(r) - dp(l - 1)); return 0; }
|