CF1036C Classy Numbers 题解

· · 题解

思路

数位 DP。

设 f_{i,j,k} 表示所有位数为 i,最高位为 j,有 k 个数位上的数字为 1\sim 9 的数字个数。

转移:

\displaystyle\sum_{c=0}^9 f_{i-1,c,k-1}\ (j\ne 0,k\ne 0)\end{cases}

初始值:f_{1,0,0}=1,f_{1,1\sim 9,1}=1。

定义 len(x) 表示 x 的位数,d(x,i) 表示 x 的第 i 为上的数字,query(x) 表示 1\sim x-1 中有多少个“好数”,答案为 query(r+1)-query(l)。

1. 位数为 $1\sim len(x)-1$ 的“好数”。 总数为 $\displaystyle\sum_{i=1}^{len(x)-1}\sum_{j=1}^9\sum_{k=1}^3 f_{i,j,k}$。 1. 位数为 ${len}(x)$ 的“好数”,因为要去掉前导零,把最高位单独考虑: - 考虑第 $1\sim len(x)-1$ 位都与 $x$ 相同,且第 $len(x)$ 位不超过 $d(x,len(x))$ 的“好数”,总数为 $\displaystyle\sum_{i=1}^{d(x,len(x))-1}\sum_{j=0}^3 f_{len(x),i,j}$。 - 考虑第 $1\sim i$ 位都与 $x$ 相同,且第 $i$ 位不超过 $d(x,i)$ 的“好数”,总数为 $\displaystyle\sum_{i=1}^{len(x)-1}\sum_{j=0}^{d(x,i)-1}\sum_{k=0}^{3-cnt(i)}f_{i,j,k}$,其中 $cnt(i)$ 表示 $x$ 的 $i\sim len(x)-1$ 位中有多少位为 $1\sim 9$。 ### 代码 ```cpp #include <bits/stdc++.h> using namespace std; int t, d[25]; long long l, r, f[25][25][25]; long long query(long long x) { int len = 0; long long ret = 0; while (x) d[++len] = x % 10, x /= 10; for (int i = 1; i < len; i++) for (int j = 1; j <= 9; j++) for (int k = 0; k <= 3; k++) ret += f[i][j][k]; for (int i = 1; i < d[len]; i++) for (int j = 0; j <= 3; j++) ret += f[len][i][j]; for (int i = len - 1, cnt = 0; i >= 1; i--) { if (d[i]) cnt++; for (int j = 0; j < d[i]; j++) for (int k = 0; k <= 3 - cnt; k++) ret += f[i][j][k]; } return ret; } int main() { cin >> t; f[1][0][0] = 1; for (int i = 1; i <= 9; i++) f[1][i][1] = 1; for (int i = 2; i <= 19; i++) { for (int j = 0; j <= 9; j++) { for (int k = 0; k <= 3; k++) { for (int c = 0; c <= 9; c++) { if (!j) f[i][j][k] += f[i - 1][c][k]; else if (k) f[i][j][k] += f[i - 1][c][k - 1]; } } } } while (t--) { cin >> l >> r; cout << query(r + 1) - query(l) << '\n'; } return 0; } ```