题目
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
解题思路
本题数据量很大遍历暴力解法肯定超时,需要找规律。可以发现最终1的个数之和肯定是个位的1数目+十位的1数目+百位的1数目+...
,接下来需要分析的便是各个位的1个数的规律:
(1) 一位数:1-9,当N大于等于1时,有1个1。
(2) 两位数:10-99,先看个位的1数目,当N的个位数大于等于1时,则个位1的数目 = 十位数+1
,反之(N的个位数小于1),个位1的数目 = 十位数
;再看十位的1数目,当十位数等于1,那么十位1的数目 = 个位数+1
,当十位数大于1,十位1的数目 = 10
。
(3) 三位数:100-999,还是先看个位的1数目,当N的个位数大于等于1时,则个位1的数目 = N/10+1
,反之(N的个位数小于1),个位1的数目 = N/10
;再看十位的1数目,当N的十位数为1,那么十位1的数目 = (个位数+1)+百位数*10
,当十位数大于1,十位1的数目 = (百位数+1)*10
,当十位数为0,十位1的数目 = 百位数*10
;最后看百位的1数目,当百位为1时,百位1的数目 = N-百位数*100+1
,反之,百位1的数目 = 100
。
(4) 四位数:1000-9999,有:
个位1的数目 = (个位>=1)?(N/10+1):(N/10);
十位1的数目 = (十位>1)?((N/100+1)*10):((十位==0)?(N/100*10):(N/100*10+个位数+1));
百位1的数目 = (百位>1)?((N/1000+1)*100):((百位==0)?(N/1000*100):(N/1000*100+十位数*10+个位数+1));
千位1的数目 = (千位>1)?1000:(N-千位数*1000+1);
由此可见规律,根据以上规律写代码即可。
易错点
我想到的测试用例如下:
输入 | 输出 | 目的 |
---|---|---|
1 | 1 | 测试一位数字时程序能否正确输出 |
5 | 1 | a[0]和a[len-1]是同一个数的时候,不要累计加2次1(测试点5原理) |
12 | 5 | 样例 |
20 | 12 | 测试个位为0时,1的个数能否正确输出 |
101 | 23 | 测试中间数字为0能否正确输出 |
111 | 36 | 测试最高位为1、个位为1、中间位为1时能否正确输出 |
以上用例都过了,提交便AC了。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> a;
int i,j,len;
char temp;
long int t,num=0,result=0;
while (scanf("%c",&temp)!=EOF && temp>47 && temp<58){
a.push_back(temp-48);
}
len = a.size();
if (len==1)
printf("1");
else
{
t = pow(10,len-1);
for (i=0;i<len;i++)
num+=pow(10,len-1-i)*a[i];
result += ((a[len-1]>=1)?(num/10+1):(num/10));//个位1的数目 = (个位>=1)?(N/10+1):(N/10)
result += ((a[0]>1)?t:(num-t*a[0]+1));//最高位位1的数目
for (i=1;i<(len-1);i++)//中间位数遍历
{
if (a[i]>1)
{
t = pow(10,len-i);
result += (num/t+1)*(t/10);//如十位数:(N/100+1)*10
}
else if (a[i]==1)//如:百位数:(N/1000*100+十位数*10+个位数+1)
{
t = pow(10,len-i);
result += num/t*(t/10)+1;//对应于上式的加一
for (j=i+1;j<len;j++)
{
t = pow(10,len-j-1);
result += a[j]*t;
}
}
else if (a[i]==0)
{
t = pow(10,len-i);
result += num/t*(t/10);
}
}
printf("%ld",result);
}
return 0;
}