计算机算法设计与分析1-1
问题描述:
一本书的页码从自然数1开始计数,直到自然数n。书的页码按照通常的习惯编排,每个页码都不包含多余的前导数字0。例如,第6页用数字6表示,而不是06或006等。数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,...,9。
本来就是暴力写的,看了看数据范围到e9,O—O
然后看了看答案的递归公式,咋推出来的我也布吉岛,还现学了一波差分方程怎么解,最后还是参考了大佬的博客。
下面说一下步骤
1.确定数字长度,log10(n)+1,如1000长度为4
2.分区间,区间长度为10^n
如230,区间长度100,000-099,100-199 (至于为什么不算200-230,下面会处理)
3.在每个区间内0-9这10个数字出现的次数相同(除了首位,即100-199的1会多出一些)
将0-9除了首位外出现的次数算出来
4.计算首位出现的次数
5.将算过的地方去掉,并且处理0(如10300,在取余得到300时要将中间的0计算求和)
6.递归处理余数
7.得到结果后减去多算的0,这也就是网上说的补0递归法
#include<bits/stdc++.h>
using namespace std;
int ans[10];
void solve(int n)
{
int len=log10(n)+1;
int digit=n/(round(pow(10,len-1)));
for(int i=0;i<=9;i++)
ans[i]+=digit*(len-1)*round(pow(10,len-2));
for(int i=0;i<digit;i++)
ans[i]+=round(pow(10,len-1));
int tep=n%(int)round(pow(10,len-1));
ans[digit]+=1+tep;
if(tep==0)
{
ans[0]+=len-1;
return ;
}
else
{
int len1=log10(tep)+1;
ans[0]+=(tep+1)*(len-len1-1);
return solve(tep);
}
}
int main()
{
int n;
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
scanf("%d",&n);
solve(n);
int len=log10(n)+1;
for(int i=0;i<len;i++)
ans[0]-=round(pow(10,i));
for(int i=0;i<=9;i++)
printf("%d\n",ans[i]);
return 0;
}