紫书 例题 10-22 UVa 1640(数位统计)

这道题的题解有几个亮点

一个是每次只统计一个数字来简化思维

一个是统计当前位数的时候分三个部分来更新答案

具体看代码,有注释

#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;

const int MAXN = 10;
int pow[MAXN], cnt[MAXN];

int f(int d, int n) //分单个数字来统计,简化了思维过程 
{
	char s[MAXN];
	sprintf(s, "%d", n);
	int len = strlen(s), ans = 0;
	
	REP(i, 1, len)  //如果是四位数,那么一,二,三位数的数字的个数可以直接统计,以此类推 
	{
		if(i == 1) ans++;
		else
		{
			ans += 9 * cnt[i-1];
			if(d > 0) ans += pow[i-1]; //注意首位要单独出来统计 
		}
	}
	
	int pre[10]; //前i位数d出现的次数 
	REP(i, 0, len)
	{
		pre[i] = s[i] - '0' == d ? 1 : 0;
		if(i > 0) pre[i] += pre[i-1];
	}
	
	REP(i, 0, len)
	{
		int maxd = s[i] - '0';
		int mind = (i == 0 && len > 1);	 //首位不为0,只有0除外 
		REP(digit, mind, maxd) 
		{
			ans += cnt[len-i-1]; //当前位数的后面的数 
			if(i > 0) ans += pre[i-1] * pow[len-i-1]; //当前位数的前面的数 
			if(digit == d) ans += pow[len-i-1]; //当前位数 
		}
	}
	
	return ans;
}

int main()
{
	pow[0] = 1;
	REP(i, 1, 9)
	{
		pow[i] = pow[i-1] * 10; //10的i次方 
		cnt[i] = pow[i-1] * i; //i位数中每个数字出现的次数(0可以为首位) 
	}
	
	int a, b;
	while(~scanf("%d%d", &a, &b) && a)
	{
		if(a > b) swap(a, b);
		REP(d, 0, 10)
		{
			if(d) printf(" ");
			printf("%d", f(d, b + 1) - f(d, a));
		}	
		puts("");
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34416123/article/details/81110995