统计数字问题

来源:互联网 发布:opengl es2.0编程指南 编辑:程序博客网 时间:2024/04/30 15:46

最近有些堕落了。 要赶紧调整过来。  先写篇解题报告试试。。。

题目描述:

      一本书的页码从自然数1开始顺序编码直到自然数N。书的页码不包含前导数字0。例如,第6也用数字6表示,而不是06。要求给定书总页码n。计算书的全部页码中分别用到多少次数字0,1,2,3,4…9.

      输入  10    输出 1 4 1 1 1 1 1 1 1 1 

      为了方便考虑, 补全前导0。  考察由0,1,……9组成的所有n位数 。从n个0到n个9。共10^n个n位数。其中每个数字出现相同的n*10^(n-1)次。现在利用这个结论来举个例子计算一下334。

      从000到334。  首先考虑从00到99,100到199 200到299中个位和十位上每个数字出现了3*10 次(先不考虑百位)。然后考虑百位上0,1,2,3 这四个数分别出现多少次,很明显,0,1,2 分别出现100次,3 出现了35次(34+1)。 计算完这些之后,现在只有从00到34上数字出现的次数没考虑了。同样的方法,计算00到34,首先考虑0到9 10到19  20 到29 个位上每个数字出现3*1次。百位上0,1,2分别出现10次,3 出现5次(4+1)。 计算完这些后,只剩下从0到4 上数字出现的次数需要考虑了,这就很明显了。计算完之后,还需要将前导0减掉。前导0的出现是很有规律的,比如说000到334,我们增加的前导0的个数为3+2*9+1*90=111。可以注意到整个算法具有很明显的相似子结构,可以用递归来做,但同样用循环也是可以实现的。

     代码如下:

#include <stdio.h>
#include <string.h>
int ans[12],bs[12],f[12];
int reduce(int n)//计算前导0的个数
{
 int count=0,i,j;
 for(i=1;i<n;i++){
  count=count+(n-i)*9*bs[i-1];
 }
 return count+n;
}
int cnt(char val[],int l,int len)
{
 int count=0;
 for(int i=l;i<len;i++){
  count=count*10+val[i]-'0';
 }
 return count+1;
}
int main()
{
 int len,i,j;
 char val[11];
 for(i=1,bs[0]=1;i<10;i++){
     bs[i]=bs[i-1]*10;
 }
 for(i=1,f[0]=0;i<10;i++){
  f[i]=10*f[i-1]+bs[i-1];
 }
 while(scanf("%s",val)!=EOF){
  len=strlen(val);
  memset(ans,0,sizeof(int)*10);
  for(i=0;i<len;i++){
   int wei=len-i,v=val[i]-'0';
   for(j=0;j<10;j++){
    ans[j]=ans[j]+v*f[wei-1];
   }
   for(j=0;j<v;j++){
    ans[j]=ans[j]+bs[wei-1];
   }
   ans[v]=ans[v]+cnt(val,i+1,len);
  }
  ans[0]=ans[0]-reduce(len);
  for(i=0;i<10;i++){
   printf("%d/n",ans[i]);
  }
 }
 return 0;
}