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;
}

本人第一篇题解~

不喜勿喷~ ​

posted @ 2022-07-18 12:01  LittleMoMol  阅读(111)  评论(0编辑  收藏  举报
*/