The task is simple: given any positive integer N, you are supposed to count the total number of 1’s in the decimal form of the integers from 1 to N. For example, given N being 12, there are five 1’s in 1, 10, 11, and 12.
Input Specification:
Each input file contains one test case which gives the positive N (≤2
30
).
Output Specification:
For each test case, print the number of 1’s in one line.
Sample Input:
12
Sample Output:
5
分析:
一、首先想到暴力求解,几分钟得22分,很值
二、这是一个数学问题,计数1的个数,可以计算每数位(个位、十位…)出现1的次数,相当于一个排列组合题,从个位开始计算,例(80132这个数)分情况:
1、当计算千位时,该数为0,则固定该位为1的情况时,出现的次数由该位所在的数位和该位左边的数决定,比如:71000,71001…71999。一共有1000种,而左边数为0-7时千位可以出现1,所以组合一波,出现8 * 1000种,所以当该位数为0时,该位出现1的次数等于左边的数(8)乘以该位所在的数位(1000)
2、当计算百位时,该数为1,和上面思路一样,只是多了
当数到80100-80132的情况;所以该位出现一的次数为左边的数(80)乘以该位所在的数位(100)+右边的数(32)+ 1
3、当计算百位时,该数为3,也和上面思路相似;只是和情况1计算左边数多了1,这回左边的数为0-801,而不是0-701;因为,该数大于了1,已经把8011*的情况占完,所以该数位出现1的个数为(左边的数(801)+ 1) 数位(10)
最后依次按上面3种情况计算,加上每位出现1的次数就OK了
我的代码:
#include<cstdio>
int main()
{
int n,cnt = 0,right = 0,a = 1;
scanf("%d",&n);
while (n != 0)
{
if (n % 10 == 0)
cnt += n / 10 * a;
else if (n % 10 == 1)
cnt += n / 10 * a + right + 1;
else
cnt += (n / 10 + 1) * a;
right = right + n % 10 * a;
n = n / 10;
a *= 10;
}
printf("%d",cnt);
return 0;
}