UVa 1640 The Counting Problem (数位DP)

题目

题目大意

给出\(a\)\(b\), 统计\(a\)\(b\)(包含\(a\)\(b\))之间的整数中, 数字\(0, 1, 2, 3, 4, 5, 6, 7, 8, 9\)分别出现了多少次。\(1 ≤ a, b ≤ 10^8\)。注意, \(a\)有可能大于\(b\)

题解

\(f_d(n)\)表示\(0 \cdots n\)中数字\(d\)出现的个数, 则求的是\(f_d(a) - f_d(b - 1)\)

暴力显然是会\(TLE\)的, 我们可以分段来求。例如我们要求\(0 \cdots 234\)中每个数字的个数, 可以分成一下几个区间:

  1. \([0, 9]\)
  2. \([10, 99]\)
  3. \([100, 199]\)
  4. \([200, 229]\)
  5. \([230, 234]\)

递归求解就可以了。

代码

#include <cstdio>
#include <cstring>
int a[10], b[10];
inline void DepthFirstSearch(const int &n, const int &m, register int *arr) {
	register int x(n / 10), y(n % 10), temp(x);
	for (register int i = 1; i <= y; i++) {
		arr[i] += m;
  }
	for (int i = 0; i < 10; i++) {
		arr[i] += m * x;
  }
	while (temp) {
		arr[temp % 10] += m * (y + 1);
		temp /= 10;
	}
	if (x) {
		DepthFirstSearch(x - 1, m * 10, arr);
  }
}
int main(int argc, char const *argv[]) {
	register int x, y;
	while (~scanf("%d %d", &x, &y) && (x || y)) {
		if (x > y) x ^= y ^= x ^= y;
    memset(a, 0, sizeof(a)),
		memset(b, 0, sizeof(b));
		DepthFirstSearch(x - 1, 1, a),
		DepthFirstSearch(y, 1, b);
		for (register int i(0); i < 10; ++i) {
      printf(i == 9 ? "%d\n" : "%d ", b[i] - a[i]);
    }
	}
	return 0;
}
posted @ 2018-09-29 11:48  Acenaphthene  阅读(201)  评论(0编辑  收藏  举报