关于c语言中的经典页码问题
来源:牛客网
题目描述
输入描述:
输入书的总页码一个整数n。
输出描述:
输出总共10行。在第k行输出页码中用到数字k-1的次数。(k=1,2,...,10)
一开始,我是直接暴力解法,把每个数的每一位得出来的数字依次相加,设一个数组来记录0到9的数字个数,然后牛客说我超时了,用dev的时候发现在1e9的时候甚至要27s。想了很久没想明白,之后我借鉴了一个大佬的想法,直接算每一个数字的个数,
通过一些规律来计算。
下面是我对那个思路的一些理解
我们先设置一个数,以11459为例
先从1开始,从个位开始数,1,2,3,4,5,6,7,8,9,10每十位就有一个数的个位上是1,那么11459/10=1145......9,一共有1145个10,就有1145个1。由于还余了9,注意9大于1,那么还有11450,11451,11452...11459,
这九个数没算,还少了一个1,我们就还要加一个1,所以个位上一共有1146个1;
现在从十位开始,11,12,13,14,15,16,17,18,19,20,...,99每百位就有十个数的十位上是1,那么11459/100=114.....59,一共有114个100,就有114*10个1。由于还余了59,注意5大于1,那么还有11410,11411,
...,11419没算,还少了十个1,我们就还要加10个1,所以十位上一共有1150个1;
从百位开始,也遵循上面的思想,11459/1000=11......459,4大于1,所以百位上有11*100+100个1,即1200个1;
从千位开始,对于1来说就有些特别了,因为11459/10000=1......1459,所以有1*1000个1,因为1等于1,所以还有11000,11001,11002...,11459上的千位上的1没有数,从0开始到459有460个数,那就要再加460,
即1460个1;
万位也是如此,11459/100000=0......11459,所以有0*10000个1,1等于1,就有10000,10001,10002...,11459上的万位上的1没有数,从0到1459有1460个数,那就要再加1460个1;
最后一共有1146+1150+1200+1460+1460=6416个1;
同理2,3,4,5...,9也是这么算
对于6为例
个位11459/10=1145...9>6 1145*1+1;
十位11459/100=114...59<60 114*10;
百位11459/1000=11...459<600 11*100;
千位11459/10000=1...1459<6000 1*1000;
万位11459/100000=0...11459<60000 0*10000;
一共有1146+1140+1100+1000+0=4386个6;
再来考虑特殊的0,还是以11459为例
从个位开始,11459/10=1145...9>0 ,但此时不能单纯的用1145*1+1了,因为11450是被计算到那1145个0里面了
(你看1,2,3,4,5,6,7,8,9,10,在出现0的时候进位了,那么这个0在11459/10=1145时就被计算到了)
所以个位上有1145*1个0;
十位,11459/100=114...59>10 114*10;
百位,11459/1000=11...459>100 11*100;
千位,11459/10000=1...1459>1000 1*1000;
万位,11459/100000=0...11459>10000 0*10000;
一共有1145+1140+1100+1000+0=4385个0;
下面是自己写的代码
#include <stdio.h>
long sum1(long n, int i)
{
long sum = 0, m, s = 1, panduan;
int k = n;
if (i == 0)
{
while (k > 0)
{
m = k / 10;//每n个里面有0.1n个零(n大于或等于10且个位为零)
sum += m * s;//计算总和
s *= 10;//从个位开始计算
//从个位开始计算
//个位上每十个有一个零
//十位上每百个有十个零
//......
//直到末位
k /= 10;//算完个位算十位,依次下去
}
}
else
{
while (k > 0)
{
m = k / 10;//每n个里面有0.1n个i(n大于或等于10且个位为零)
sum += m * s;//计算总和
panduan = k % 10;//判断是否有少加的数字
if (panduan > i) {
sum += s;//比如9大于5,那如果是个位上就少算一个
//十位上就少算10个
}
if (panduan == i)
{
sum += n - k * s + 1;//如11459,在千位上是1等于1;
//则从1000到1459有460个千位的1没算;
//从10000到11459有1460个万位的1没算;
}
s *= 10;//从个位开始计算
//个位上每十个有一个零
//十位上每百个有十个零
//......
//直到末位
k /= 10;//算完个位算十位,依次下去
}
}
return sum;
}
int main()
{
long n, i, m;
scanf("%ld", &n);
for (i = 0; i <= 9; i++)
{
m = sum1(n,i);
printf("%ld\n", m);
}
return 0;
}