最近有些墮落了。 要趕緊調整過來。 先寫篇解題報告試試。。。
題目描述:
一本書的頁碼從自然數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;
}