(Realx 数论1.28)POJ 2282 The Counting Problem(区间统计数字:统计a、b之间各个数字(0~9)出现的次数)


题意:

  统计两个整数a,b之间各个数字(0~9)出现的次数,如1024和1032,他们之间的数字有1024 1025 1026 1027 1028 1029 1030 1031 1032 总共有100,10133等等。

分析:

  因为前导0的干扰,为了计算方便暂时都先计算在内,之后再减;

  如果是0~199,那么百位上的01各出现一次,s剩下的就是两个00~99,总共两百个二位数,而每个数出现的次数都一样,都是2*(99-00+1)/10;

  那么任意的数都可以分解成类似的数字,如3426,则可以分成0000~2999,3000~3399,3400~3419,3420~3426几个部分各自计算,再求和按位减去前导0的个数。




#include <iostream>
#include <cstdio>

using namespace std;

/**
 * 计算从0到s字符串所代表的数字中0~9各个数字出现的次数..
 *
 */
void cal(char s[], int num[]) {
	int i, j, k, n, t, m = atoi(s);//atoi(s).把字符串转换成整型数。ASCII to integer 的缩写。
	n = (int) strlen(s);
	for (i = k = 1; i < n; i++)
		k *= 10, num[0] -= k;
	for (i = 0; i < n; i++, k /= 10) {
		for (j = 0; j < s[i] - '0'; j++)
			num[j] += k;
		for (t = 0; t < 10; t++)
			num[t] += k / 10 * (n - i - 1) * j;
		if (i + 1 < n)
			num[j] += atoi(s + i + 1);
		num[j]++;
	}
}

int main() {
	int n, m;
	int a[11], b[11];
	char str[25];
	while (scanf("%d%d", &n, &m) != EOF, n || m) {
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));

		if (n > m) {
			int temp = n;
			n = m;
			m = temp;
		}

		/**
		 * 函数功能:把格式化的数据写入某个字符串
		 * 函数原型:int sprintf( char *buffer, const char *format [, argument] … );
		 * 返回值:字符串长度(strlen)
		 *例子:
		 *char* who = "I";
		 *char* whom = "CSDN";
		 *sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. "  这字符串写到s中
		 *sprintf(s, "%10.3f", 3.1415626); //产生:" 3.142"
		 */
		sprintf(str, "%d", n - 1); //将格式化的数据写入某个字符串

		cal(str, a);

		sprintf(str, "%d", m);

		cal(str, b);

		int i;
		for (i = 0; i < 10; ++i) {
			printf("%d ", b[i] - a[i]);
		}
		printf("\n");
	}

	return 0;
}


你可能感兴趣的:((Realx 数论1.28)POJ 2282 The Counting Problem(区间统计数字:统计a、b之间各个数字(0~9)出现的次数))