-
[1475] Bachelor
- 时间限制: 1000 ms 内存限制: 65535 K
- 问题描述
-
炎热的暑期集训就要结束了,在这短短的20天,大家都很努力,因为很多都是光棍嘛。balabala
所以 Marknoon 先森一直耿耿于怀,毕竟他也是单身嘛。
有一天,Marknoon 先森看着一串数字,发现了那个跟他同命相连的数字1,所以他就开始无聊起来,想知道从数字1到数字N,一共出现了几个1。
例如N=12,则1的个数为5,出现1的数字分别为1,10,11,12。
- 输入
-
输入一个数N(1 <= N <= 2147483647)。
- 输出
-
输出从1到N中所有数字里出现 1 的个数。
- 样例输入
-
3
13
123
- 样例输出
-
1
6
57
- 提示
-
无
- 来源
-
Hungar
按位置计算,即分别计算个位,十位,百位,千位 。。。的 1 出现的次数,然后将他们的个数和输出
这里以 2145 为例进行说明: 个位为 1 的情况 : _ _ _ 1 横线部分 可以是 000 到 214 的任意数字 所以个位 一共有 215个 1 ------- (214 + 1)
十位为 1 的情况: _ _ 1 _ 横线部分 可以是 000 到 219 的任意数字 十位 一共有 220 个 1 ------- (21 +1)*10
百位为 1 的情况: _ 1 _ _ 横线部分 可以是 000 到 245 的任意数字 百位 一共有 246 个 1 ------ 2 * 100 +45 +1
千位为 1 的情况: 1 _ _ _ 横线部分 可以是 000 到 999 的任意数字 千位 一共有 1000 个 1 ------ (0 + 1)* 1000
当然 还有 为 0 的情况 如果是 2105 的话 则 有 21* 10 ---- 十位 有 210 个 1
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char str[20];
int digit[20];
long long Zero[20]={1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12};
int cal(int l,int r){ //得到digit数组里面[i,j]区间构成的数
int ans=0;
for(int i=l;i<=r;i++)
ans=ans*10+digit[i];
return ans;
}
int main(){
//freopen("input.txt","r",stdin);
while(~scanf("%s",str)){
int len=strlen(str);
for(int i=0;i<len;i++)
digit[i]=str[i]-'0';
long long ans=0;
int l,r;
for(int i=0;i<len;i++){
l=cal(0,i-1);
if(digit[i]>1) //如果数字大于1 则用左边 digit[0,i-1] 构成的数 加1 乘上 10的(右边位数)次方
ans+=(l+1)*Zero[len-1-i];
else if(digit[i]==1){ //如果数字等于1 则用左边 digit[0,i-1] 构成的数 乘上 10的(右边位数)次方 后 加上 右边digit[i,len-1] 构成的数 再加上1
r=cal(i+1,len-1);
ans+=l*Zero[len-1-i]+r+1;
}else if(digit[i]==0) //如果数字等于0 则用左边digit[0,i-1] 构成的数 直接乘上 10的(右边位数)次方
ans+=l*Zero[len-1-i];
}
cout<<ans<<endl;
}
return 0;
}