给点一个数
计算1-n之间1的个数
如 11 有两个1
题目很短,思考过程却不是那么容易,刚开始开了个字符串慢慢算,只能得到22分
如下,不能得到全部,其他全部超时
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int amax=9;
int k;
int cal(char s[]){
int sum=0;
for(int i=16;i>=0;i--){
sum=sum*10+s[i]-'0';
}
return sum;
}
void add(char s[]){
for(int i=0;i<=k;i++){
if(s[i]<'9'){
s[i]+=1;
break;
}
else if(s[i]=='9'){
s[i]='0';
}
}
}
int ji(char s[]){
int cnt=0;
for(int i=k;i>=0;i--){
if(s[i]=='1') cnt++;
}
return cnt;
}
int main(int argc, char const *argv[])
{
int N;
cin>>N;
char s[50];
sprintf(s,"%d",N);
k=strlen(s)+1;
int cnt=0;
char emm[50];
for(int i=0;i<=49;i++){
emm[i]='0';
}
while(1){
int d=cal(emm);
if(d==N) break;
add(emm);
cnt+=ji(emm);
}
printf("%d\n",cnt );
return 0;
}
看了看大神的blog
自己理解一下
https://blog.csdn.net/tiantangrenjian/article/details/19908885
先看1位数的情况。
如果N = 3,那么从1到3的所有数字:1、2、3,只有个位数字上可能出现1,而且只出现1次,进一步可以发现如果N是个位数,如果N>=1,那么f(N)都等于1,如果N=0,则f(N)为0。
再看2位数的情况。
如果N=13,那么从1到13的所有数字:1、2、3、4、5、6、7、8、9、10、11、12、13,个位和十位的数字上都可能有1,我们可以将它们分开来考虑,个位出现1的次数有两次:1和11,十位出现1的次数有4次:10、11、12和13,所以f(N)=2+4=6。要注意的是11这个数字在十位和个位都出现了1,但是11恰好在个位为1和十位为1中被计算了两次,所以不用特殊处理,是对的。再考虑N=23的情况,它和N=13有点不同,十位出现1的次数为10次,从10到19,个位出现1的次数为1、11和21,所以f(N)=3+10=13。通过对两位数进行分析,我们发现,个位数出现1的次数不仅和个位数字有关,还和十位数有关:如果N的个位数大于等于1,则个位出现1的次数为十位数的数字加1;如果N的个位数为0,则个位出现1的次数等于十位数的数字。而十位数上出现1的次数不仅和十位数有关,还和个位数有关:如果十位数字等于1,则十位数上出现1的次数为个位数的数字加1;如果十位数大于1,则十位数上出现1的次数为10。
f(13) = 个位出现1的个数 + 十位出现1的个数 = 2 + 4 = 6;
f(23) = 个位出现1的个数 + 十位出现1的个数 = 3 + 10 = 13;
f(33) = 个位出现1的个数 + 十位出现1的个数 = 4 + 10 = 14;
…
f(93) = 个位出现1的个数 + 十位出现1的个数 = 10 + 10 = 20;
接着分析3位数。
如果N = 123:
个位出现1的个数为13:1, 11, 21, …, 91, 101, 111, 121
十位出现1的个数为20:10~19, 110~119
百位出现1的个数为24:100~123
f(123)= 个位出现1的个数 + 十位出现1的个数 + 百位出现1的次数 = 13 + 20 + 24 = 57;
同理我们可以再分析4位数、5位数。
根据上面的一些尝试,下面我们推导出一般情况下,从N得到f(N)的计算方法:
假设N=abcde,这里a、b、c、d、e分别是十进制数N的各个数位上的数字。如果要计算百位上出现1的次数,它将会受到三个因素的影响:百位上的数字,百位以下(低位)的数字,百位(更高位)以上的数字。
三种情况
如果百位上的数字为0,则可以知道,百位上可能出现1的次数由更高位决定,比如12 013,则可以知道百位出现1的情况可能是100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共有1 200个。也就是由更高位数字(12)决定,并且等于更高位数字(12)×当前位数(100)。
如果百位上的数字为1,则可以知道,百位上可能出现1的次数不仅受更高位影响,还受低位影响,也就是由更高位和低位共同决定。例如对于12 113,受更高位影响,百位出现1的情况是100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共1 200个,和上面第一种情况一样,等于更高位数字(12)×当前位数(100)。但是它还受低位影响,百位出现1的情况是12 100~12 113,一共114个,等于低位数字(113)+1。
如果百位上数字大于1(即为2~9),则百位上可能出现1的次数也仅由更高位决定,比如12 213,则百位出现1的可能性为:100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,12 100~12 199,一共有1 300个,并且等于更高位数字+1(12+1)×当前位数(100)。
#include <bits/stdc++.h>
using namespace std;
int cal(int n){
int cnt=0;
int factor=1;
int higher,lower,cur;
while(n/factor){
higher=n/(factor*10);
lower=n-n/factor*factor;
cur=(n/factor)%10;
if(cur==0){
cnt+=higher*factor;
}
else if(cur==1){
cnt+=higher*factor+lower+1;
}
else{
cnt+=higher*factor+factor;
}factor*=10;
}
return cnt;
}
int main(){
int n;
cin>>n;
printf("%d\n",cal(n));
return 0;
}