【洛谷P2602】【数字计数】【来自小zhu的奥数计数方法】

题目描述

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

输入格式

输入文件中仅包含一行两个整数a、b,含义如上所述。

输出格式

输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。

输入样例

1 99

输出样例

9 20 20 20 20 20 20 20 20 20
分析:
小zhu教给我的计数方法:例如213中有多少个1

个位1的个数: t 1 = 213 / 10 = 21 , t 2 = 213 % 10 = 3 t1 = 213 / 10 = 21, t2 = 213 \% 10 = 3 t1=213/10=21,t2=213%10=3 t 1 t1 t1 为从 0 到 t 1 − 1 t1-1 t11 每个数后面都可以加一个 1,而 t 2 = 3 > = 1 t2 = 3 >= 1 t2=3>=1 所以 t 1 t1 t1 后也可以加1,因为 t 2 > = ( 1 + 1 ) t2 >= (1 + 1) t2>=(1+1) 所以 t 2 t2 t2 后面可以加 1 × 1 1 \times 1 1×1 个 1,所以个位有 21 + 1 = 22 21 + 1 = 22 21+1=22 个 1。

十位1的个数: t 1 = 213 / 100 = 2 , t 2 = 213 % 100 = 13 t1 = 213 / 100 = 2, t2 = 213 \% 100 = 13 t1=213/100=2,t2=213%100=13 t 1 t1 t1 为从 0 到 t 1 − 1 t1-1 t11 每个数后面都可以加一个 1–是十位,那么个位又有 0-9 的选择,所以此时加的是 t 1 × 10 t1\times10 t1×10 t 2 = 13 > = 1 × 10 t2 = 13>=1\times10 t2=13>=1×10 所以 t 1 t1 t1 后面可以加 1,但是可以加多少个 1 呢,因为 t 2 = 13 < ( 1 + 1 ) × 10 t2 = 13 < (1 + 1)\times10 t2=13<(1+1)×10,所以 t 1 t1 t1 后面不能加 1 × 10 1\times10 1×10 个 1,只能加 t 2 − 1 × 10 + 1 = 4 t2 - 1\times10 + 1 = 4 t21×10+1=4 个 1(这里加 1 是因为从 0-3),所以十位有 t 1 × 10 + 4 = 24 t1\times10+4=24 t1×10+4=24 个 1。

百位1的个数: t 1 = 213 / 1000 = 0 , t 2 = 213 % 1000 = 213 t1 = 213 / 1000 = 0, t2 = 213 \% 1000 = 213 t1=213/1000=0,t2=213%1000=213 t 1 t1 t1 为从 0 到 t 1 − 1 t1-1 t11 每个数后面都可以加一个 1–是百位,那么十位和个位又有 100 种选择,所以此时加的是 t 1 × 100 t1\times100 t1×100 t 2 = 213 > = 1 × 100 t2=213>=1\times100 t2=213>=1×100 所以 t 1 t1 t1 后面可以加 1,加多少个 1 呢,因为 t 2 = 213 > = ( 1 + 1 ) × 100 t2 = 213 >= (1 + 1)\times100 t2=213>=(1+1)×100,所以 t 1 t1 t1 后面可以加 1 × 100 1\times100 1×100 个1,所以百位有 t 1 × 100 + 1 × 100 = 100 t1\times100 + 1\times100=100 t1×100+1×100=100 个 1。

213中共有 22 + 24 + 100 = 146 22+24+100 = 146 22+24+100=146个1。

关于2-9的计数和1的类似,需要注意的是0的计数,

  1. 首位不能为0
  2. 上面计数1的时候, t 1 t1 t1为从0到 t 1 − 1 t1-1 t11每个数后面都可以加1,但是对于计数0来说,0的后面再加0就重复了,所以对于计数0, t 1 t1 t1代表的是从1到 t 1 − 1 t1-1 t11每个数后面都可以加1,所以这里加和的时候要注意 t 1 − 1 t1-1 t11。对于利用 t 2 t2 t2来判断可以加多少个0是同样的。
AC代码
#include
#define LL long long
using namespace std;
LL a, b, ans;
LL solve(LL x, int i) {
	LL cnt = 0, c = 10, t1, t2; 
	if(i == 0) {
		while(1){
			t1 = x / c;
			t2 = x % c;
			if(t1 == 0)
				break;
			cnt += (t1 - 1) * c / 10;
			if(t2 >= c / 10)
				cnt += c / 10;
			else 
				cnt += t2 + 1; 	
			c = c * 10;
		}
	}
	else {
		do {
			t1 = x / c;
			t2 = x % c;
			cnt += t1 * c/10;
			if(t2 >= (i + 1) * c / 10)
				cnt += c/10;
			else if(t2 >= i * c / 10)
				cnt += t2 - i * c / 10 + 1;
			c = c * 10; 
		}while(t1 > 0);
	}
	return cnt;
}
int main()
{
	char in[100];
	cin >> a >> b;
	for(int i = 0; i < 10; ++i) {
		ans = solve(b, i) - solve(a - 1, i); 
		if(i == 0)
			cout << ans;
		else 
			cout << " " << ans;
	}
	cout << endl;
	return 0;
}

你可能感兴趣的:(数学,思维)