题目大意:
给定正整数 a a a和 b b b,求在 [ a , b ] [a,b] [a,b]区间内,各个数码出现了几次
解题思路:
- 设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]为从最高位到第 i i i位有 k k k个 j j j的方案数
- 然后记忆化搜索即可,注意:不能有前导0
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll num[20];
ll a, b, dp[20][20]; // 省略了一维将中间那维省略掉了,因为对每个k都进行一遍即可
ll read() {
ll X = 0, p = 1; char c = getchar();
for (; c > '9' || c < '0'; c = getchar()) if (c == '-') p = -1;
for (; c <= '9' && c >= '0'; c = getchar()) X = X * 10 + c - '0';
return X * p;
}
ll dfs(int pos, int dig, bool limit, bool zero, ll res) {
if (!pos) return res;//res即代表最高位到pos位有多少个dig
if (!limit && !zero && dp[pos][res] != -1) return dp[pos][res];
int up = limit ? num[pos] : 9;
ll ans = 0;
for (int i = 0; i <= up; i++)
ans += dfs(pos - 1, dig, limit && i == num[pos], zero && i == 0, res + (i == dig && ((!zero) || i)));
if (!limit && !zero) dp[pos][res] = ans;
return ans;
}
ll solve(ll x, ll dig) {
int cnt = 0;
memset(dp, -1, sizeof(dp));
while (x) num[++cnt] = x % 10, x /= 10;
return dfs(cnt, dig, true, true, 0);
}
int main() {
a = read(), b = read();
for (int i = 0; i <= 9; i++) printf("%lld ", solve(b, i) - solve(a - 1, i));
}