1. 程式人生 > >UVa 1640 The Counting Problem (數位DP)

UVa 1640 The Counting Problem (數位DP)

first clas mat string 數字 出現 cstring 區間 sca

題目

題目大意

給出\(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;
}

UVa 1640 The Counting Problem (數位DP)