Uva1225 求数字0-9在前n个正整数中出现的次数(1<=n<=10000)

//Uva1225
//求数字0-9在前n个正整数中出现的次数(1<=n<=10000)

//设n是length位数,设num为n最高位的数,设m=num*(10^(length-1)),设d是n的后length-1位数组成的数,则m=n-d。
//比如,n=123456789,n是9位数(length=9)。则m=100000000,d=23456789。
//d也可以当成是新的n,拆成两部分,则:n=1*10^8+2*10^7+3*10^6+...+8*10+9。
//将n倒序,将其倒序后的每一位储存在数组input中,从input[1]开始,令input[0]=0。
//比如:input[]={0,9,8,7,6,5,4,3,2,1},则n=input[1]+input[2]*10^1+...+input[i]*10^(i-1)+...+input[9]*10^8。
//则m=input[9]*10^8=100000000。考虑m,m是9位数(length=9),最高位为num=1。
//先来计算在前m个正整数中,0-9出现了的多少次,将结果储存在数组ans中。(calculate(1,9,ans))。
//可想象这样一个数字排列:
//100000000
// 99999999
// 99999998
// 。。。
// 10000000
//  9999999
//  。。。
//        2
//		  1
//即将1-m从下至上排列出来。
//可将其写成如下格式:
//100000000
//099999999
//099999998
// 。。。
//010000000
//009999999
//  。。。
//000000002
//000000001
//后length-1列中,每一列0-9出现次数相同,则for(i:0->9) ans[i]+=num*10^(length-1)*(length-1)/10。
//然后计算首位数字的情况。for(i:1->num-1) ans[i]+=10^(length-1)。还要ans[num]+=1。
//因为0被多记录了(9+99+999+...+99999999)次,应再减去。ans[0]-=(10^(length-1)-1)/9-(length-1)。
//以此类推。其实感觉可以从排列组合的角度解决此问题。


#include <iostream>
#include <math.h>
using namespace std;
void calculate(int num,int size,int* array);	//
int n=0;

int main()
{
	while(cin >>n)
	{
		int length=0;
		int ans[10]={0};	//ans[i]:i出现的次数。
		int input[10]={0};  //input[i]:n的第i位数。

		do	//将n的每一位数储存在input数组中。
		{
			input[++length]=n%10;
		}
		while(n/=10);

		for(int i=1;i<=length;++i)
		{
			if(input[i])
			{
				calculate(input[i],i,ans);
			}
			for(int j=1;j<i;++j)
			{
				if(input[j])
				{
					ans[input[i]]+=input[j]*pow(10,j-1);
				}
			}
		}
		for(int j=0;j<10;++j)
		{
			cout << j << " 出现的次数为: " << ans[j] << endl;
		}
		cout << endl;
	}
	return 0;
}

void calculate(int num,int size,int* array)
{
	for(int i=0;i<10;++i)
	{
		array[i]+=pow(10,size-2)*num*(size-1);
	}
	for(int j=1;j<num;++j)
	{
		array[j]+=pow(10,size-1);
	}
	array[num]+=1;
	array[0]+=(size-1)-(pow(10,size-1)-1)/9;;
}
	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值