UVa 1640 The Counting Problem (數位DP)
阿新 • • 發佈:2018-09-29
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\)中每個數字的個數, 可以分成一下幾個區間:
- \([0, 9]\)
- \([10, 99]\)
- \([100, 199]\)
- \([200, 229]\)
- \([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)