C++之數字計數演算法

老樊Lu碼發表於2018-07-29

1、問題

        輸入n,m,求n~m範圍內的所有數字中,分別輸出0~9出現的總數是多少?

 2、思路

        列舉0在個十百千位上出現的次數 
個:個位為0時,後面不需要考慮,只需考慮前面,因為0比4小,所以前面即使取到最大也不會過限,所以前面可以是1~203(因為當前位是0,所以前面不能是0)。一共203種。 
十:十位為0時,前面取1~20,後面取0~9。一共123*10種。 
百:百位為0時,因為0與當前位上限0相等,所以前面取1時,後面可以取0~99,前面取2時,後面只能取0~34。一共1*100+35種。 
千位顯然不能為0,所以總數為0。 0和1~9要分開處理,是因為字首0的問題。因為當某一位取0時,前面部分的數是不能為0的,而取1~9是可以前面為0的。
把上述思想轉化為程式碼即可。

       

// NumberFrq.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <map>

using namespace std;

#define LL long long
LL p[20];
LL ans[10] = {};

void init()
{
	p[0] = 1;
	for (int i = 1; i < 18; i++)
		p[i] = p[i - 1] * 10;
}

void solve(LL x, int f)
{
	if (x == -1)
	{
		ans[0]++;
		return;
	}
	for (int k = 1; k < 10; k++)
	{
		for (int i = 1; ; i++)
		{
			LL l = x / p[i];
			LL r = x%p[i - 1];
			LL now = x%p[i] / p[i - 1];
			if (now > k)
				ans[k] += (l + 1)*p[i - 1] * f;
			else if (now == k)
				ans[k] += (l*p[i - 1] + r + 1)*f;
			else
				ans[k] += l*p[i - 1] * f;
			if (p[i] > x)
				break;
		}
	}
	for (int i = 1; ; i++)
	{
		LL l = x / p[i];
		LL r = x%p[i - 1];
		LL now = x%p[i] / p[i - 1];
		if (now > 0)
			ans[0] += l*p[i - 1] * f;
		else
			ans[0] += ((l - 1)*p[i - 1] + r + 1)*f;
		if (p[i] > x)
			break;
	}
}

int main()
{
	LL n, m;
	init();
	cin >> n >> m;
	solve(m, 1);
	solve(n - 1, -1);
	for (int i = 0; i < 9; i++)
		printf("%lld ", ans[i]);
	printf("%lld\n", ans[9]);
	return 0;
}

 

相關文章