UVA 1640 统计问题 The Counting Problem 题解
UVA 1640 统计问题 The Counting Problem 题解
警示后人
题目不允许行末输出多于空格!!
思路
很明确,是一个数位 \(DP\),我们先考虑一些简单的问题。
No. 1 如何表示区间的个数
假如有个函数 \(\operatorname{count}(a,i)\) 可以返回 \(0 \sim a\) 之间数字 \(i\) 出现的次数,那么我们要如何表示区间 \(l \sim r\) 中相应数字出现的个数?
答案很显然,\(\operatorname{count}(r, i) - \operatorname{count}(l-1, i)\),前缀和思想。
No. 2 如何将一个十进制数的每一位存入数组中
这个很简单,我就直接上代码了。
int get_num(vector<int> num, int l, int r)
{
int res = 0;
for (int i = l; i >= r; i -- )
res = res * 10 + num[i];
return res;
}
No. 3 如何计算 \(10\) 的 \(n\) 次幂
这个似乎更简单了,可以直接调用库函数,也可以自己手写一个,都不难。
int power10(int x)
{
int res = 1;
while (x -- ) res *= 10;
return res;
}
No. 4 重点:实现 \(\operatorname{count}\) 函数
和这个相比,前三个点只是浩瀚星空中的一点灰尘。
举个栗子,令 \(n=\overline{abcdefg}\),现在尝试求第 \(4\) 位为 \(1\) 的个数,可以把 \(n\) 写成 \(\overline{xxx1yyy}\),我们分类讨论。
- \(xxx=\overline{000} \sim \overline{abc}-1\)
这种情况下,显然后面的 \(yyy\) 可以取到 \(000 \sim 999\),所以总数量就为 \(\overline{abc} \times 1000\)
- \(xxx=\overline{abc}\)
这种情况下,再细分几个情况。
- \(d < 1\)
如果 $n$ 的第 $4$ 位小于 $1$,那么无论 $\overline{yyy}$ 如何取值,都不能改变我们现在枚举的数比 $n$ 大,所以这种情况下答案是 $0$
- \(d = 1\)
显然,满足条件的 $yyy=\overline{000} \sim \overline{efg}$,所以答案是 $\overline{efg} + 1$
- \(d > 1\)
这种情况 $\overline{yyy}$ 无论如何取值都满足要求,所以答案为 $1000$
至此,我们将所有情况都不重不漏地讨论完毕了!
No. 5 特例
易知当想要统计的数字为 \(1 \sim 9\) 时上述做法毫无问题,但是数字为 \(0\) 的时候就得考虑前导零的影响了。
还拿上面的例子来说,如果尝试求第 \(4\) 位为 \(0\) 的个数,那么 \(\overline{0000efg}\) 就不是所求了,所以要减去,这将在代码中有体现。
No. 6 Code
#include <iostream>
#include <vector>
using namespace std;
const int N = 10;
int get_num(vector<int> num, int l, int r)
{
int res = 0;
for (int i = l; i >= r; i -- )
res = res * 10 + num[i];
return res;
}
int power10(int x)
{
int res = 1;
while (x -- ) res *= 10;
return res;
}
int count(int n, int x)
{
if (!n) return 0;
vector<int> num;
while (n)
{
num.push_back(n % 10);
n /= 10;
}
n = num.size();
int res = 0;
for (int i = n - 1 - !x; i >= 0; i -- ) //注意特例
{
if (i < n - 1)
{
res += (get_num(num, n - 1, i + 1) - (!x)) * power10(i); //注意特例
}
if (num[i] == x) res += get_num(num, i - 1, 0) + 1;
else if (num[i] > x) res += power10(i);
}
return res;
}
int main()
{
int a, b;
while (cin >> a >> b, a)
{
if (a > b) swap(a, b);
for (int i = 0; i <= 9; i ++ )
cout << count(b, i) - count(a - 1, i) << ' '; //前缀和思想
cout << endl;
}
return 0;
}
本人第一篇题解~
不喜勿喷~