本文主要是介绍AcWing.338. 计数问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
给定两个整数 a 和 b,求 a 和 b 之间的所有数字中 0∼9 的出现次数。
例如,a=1024,b=1032,则 a 和 b 之间共有 9 个数如下:
1024 1025 1026 1027 1028 1029 1030 1031 1032
其中
0
出现 10 次,1
出现 10 次,2
出现 7 次,3
出现 3 次等等…输入格式
输入包含多组测试数据。
每组测试数据占一行,包含两个整数 a 和 b。
当读入一行为
0
时,表示输入终止,且该行不作处理。输出格式
每组数据输出一个结果,每个结果占一行。
每个结果包含十个用空格隔开的数字,第一个数字表示
0
出现的次数,第二个数字表示1
出现的次数,以此类推。数据范围
0<a,b<100000000
输入样例:
1 10 44 497 346 542 1199 1748 1496 1403 1004 503 1714 190 1317 854 1976 494 1001 1960 0 0
输出样例:
1 2 1 1 1 1 1 1 1 1 85 185 185 185 190 96 96 96 95 93 40 40 40 93 136 82 40 40 40 40 115 666 215 215 214 205 205 154 105 106 16 113 19 20 114 20 20 19 19 16 107 105 100 101 101 197 200 200 200 200 413 1133 503 503 503 502 502 417 402 412 196 512 186 104 87 93 97 97 142 196 398 1375 398 398 405 499 499 495 488 471 294 1256 296 296 296 296 287 286 286 247
思路:求出每一位数字中0~9出现的次数
假设一个数为七位数 abcdefg ,从中求出1~abcdefg这些数字中1出现的次数,即所有位数上1出现的次数的和
比如求1在第四位上出现的次数:即求有多少如 _ _ _ 1 _ _ _ 这样的数是在范围之内的
(1)当前三位从001取到abc - 1 ,那么前三位已经决定了这个数一定是小于最大值abcdefg的,那么我们后三位可以随便取得,即从000取到999,那么这种情况有abc * 1k 种选法
(2)当前三位取abc,那么前三位已经是可取的最大值,那么要进一步进行分类讨论
1.当第四位d < 1,也就是abcdefg是永远小于abc1_ _ _的,那么这种情况取1的可能为0
2.当第四位d = 1,也就是这个数为abc1_ _ _,那么前四位已经是可取的最大的,后三位就只能去000~efg,只有这样才能保证不超范围,那么有 efg + 1 种选法
3.当第四位d > 1,也就是abc1_ _ _前四位并没有取到最大值,那么后三位随便取也可以保证在范围内,即取000 ~ 999,那么有 1k 种情况
最后,比如我们要求数A到数B之间的计数,那么我们只需要用1~B减去1~A,就能得到A~B之间的计数
注:当需要计数的数字在第一位的时候,就不需要讨论情况(1)了
#include<iostream>
#include<vector>
using namespace std;int get(vector<int> num, int l, int r) //求i前面这些位数字组成的数字(对应第一种情况)
{int res = 0;for (int i = l; i >= r; i--) {res = res * 10 + num[i];}return res;
}int power10(int x) { //求10的x次方int res = 1;while (x--)res *= 10;return res;
}int count(int n, int x) { //1到n中统计x的出现次数if (!n)return 0; //如果n等于0直接返回vector<int> num;while (n) { //获取n的每一位数num.push_back(n % 10);n /= 10;}n = num.size(); //让n等于自己的位数int ans = 0; //ans存答案for (int i = n - 1 - !x; i >= 0; i--) { //i从最高位开始枚举(计算每一位上数字组成情况),且当最高位为0的时候,从第二位开始枚举if (i < n - 1) { //如果枚举到的不是最高位ans += get(num, n - 1, i + 1) * power10(i); //i的前面这些位数字乘上10的i次方(所有的组成方法)if (!x) ans -= power10(i); //如果计算的是0的次数,那么要减去一次10的i次方(从001开始,少了一次10的i次方)}if (num[i] == x)ans += get(num, i - 1, 0) + 1; //如果这一位数字等于计算数组,数量为后面这些位组成的数字加上1else if (num[i] > x) ans += power10(i); //如果这一位是大于当前求的数字的,那么就加上10的i次方}return ans;
}int main() {int a, b;while (cin >> a >> b, a || b) { //a和b不一定谁更小if (a > b)swap(a, b);for (int i = 0; i < 10; i++)cout << count(b, i) - count(a - 1, i) << " ";puts("");}return 0;
}
这篇关于AcWing.338. 计数问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!