题意:输入n,输出从1-n之间1的个数, n ≤ 2 30 n\leq2^{30} n≤230
问题求解:
[1,10)出现1的次数为1
[1,99)出现1的次数为20,结尾为1的个数(10个)+1开头的数字(10个)
[1,999)出现1的次数为300,结尾为1(100=10*10个)+中间为1(100)+开头为1(100个)
…
通过归纳法可得: a n = 10 a n − 1 + 1 0 n − 1 , n ≥ 2 a_n=10a_{n-1}+10^{n-1},n\geq2 an=10an−1+10n−1,n≥2,其中 a 1 = 1 a_1=1 a1=1
通过推理可以直到
1
0
n
10^{n}
10n之间1的个数,但如何计算一般数字呢?
举个例子:11222可以分解成1万以内1的个数+1000以内1的个数+222以内1的个数。
1万以内1的个数为4000,万位为1的数字1222+1个(注意10000也是)
n
1
=
4000
+
1222
+
1
n_1=4000+1222+1
n1=4000+1222+1
1千以内1的个数为300,千位为1的数字222+1个(同样的1000也是)
n
2
=
300
+
222
+
1
n_2=300+222+1
n2=300+222+1
200可以分解成两个100以内,百位为1的,
n
3
=
2
×
20
+
100
n_3=2\times20+100
n3=2×20+100
20可以分解成,两个10以内,十位为1,
n
4
=
2
×
1
+
10
n_4=2\times1+10
n4=2×1+10
2不用说了,
n
5
=
1
n_5=1
n5=1
得到结果
n
=
5899
n=5899
n=5899
这里也给出归纳公式:
f
(
n
i
)
=
{
a
n
−
1
+
n
i
r
i
g
h
t
+
1
n
i
=
1
n
i
∗
a
n
−
1
+
1
0
n
−
1
n
i
!
=
1
f(n_i)=\begin{cases}a_{n-1}+n_{iright}+1& { n_i=1}\\n_i*a_{n-1}+10^{n-1}& {n_i!=1}\end{cases}
f(ni)={an−1+niright+1ni∗an−1+10n−1ni=1ni!=1
其
中
n
i
是
n
的
第
i
位
,
n
i
r
i
g
h
t
是
i
右
边
的
数
字
其中n_i是n的第i位,n_{iright}是i右边的数字
其中ni是n的第i位,niright是i右边的数字
这样一来,编程就简单了,可以用递归的方法和非递归,这里用非递归
#include<stdio.h>
#include<math.h>
long int base[11];
long sum=0;
int main()
{
int n,len,temp,remain,pow1;
scanf("%d",&n);
base[1]=1;
for(int i=2;i<=10;i++)
base[i]=10*base[i-1]+pow(10,i-1);
temp=n;
while(temp)
{
temp/=10;
len++; //计算位数
}
while(n)
{
temp=n;
pow1=pow(10,len-1);
remain=temp%pow1;
temp/=pow1;
if(temp==1)
{
sum+=base[len-1]+remain+1;
}
else
{ if(temp!=0) //注意0的时候跳过计算
sum+=temp*base[len-1]+pow1;
}
n=remain;
len--;
}
printf("%ld",sum);
return 0;
}