51Nod-题解
给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数。
例如:n = 12,包含了5个1。1,10,12共包含3个1,11包含2个1,总共5个1。
思路: 当时第一个想的就是先各位填1,然后补其它位,但当时自己给自己挖了个坑,误以为会有重复数出现,后来发现规律重复数出现并不影响计算1的个数。
例:32145 这个数我们首先把个位填1,就是_ _ _ _ 1,所以其它位可以任意填但必须在3214这个范围内,所以我们的到个位数的第一种情况—— 3214/10 + 1 = 3215 。
同理: 我们把十位数填1,结果就为 _ _ _ 1 _ 。我们先填入高位,有321+1中情况,但个位可以填0-9,所以相乘的话总共就有322*10=3220种情况。
百位填1:_ _ 1 _ _ 这时候有个问题出现了,如果按照上面的方法去填的话,结果为33*100 = 3300,但实际上我们多算了54个数,以为这个1并不是我们去填充的,而是数本身就带的,所以我们填完高位地位并没有0-9这十种情况给我们选择。所以我们需要先退一个数,高位只填到31,之后再统计个位的数。所以结果就是(31+1)* 10 +46 = 3246种。
千位的话则是普通计算规律,得出结果为4000,万位为10000,所以总的结果为 10000 +4000 +3246 +3220 +3215 = 23681
代码如下:
#include <stdio.h>
int main(void) {
int n,T,Tn; // n输入数,T表示判断当前为是否为1或者0,Tn则是用来把n拷贝一份,用于计算当位数为1的情况
int mul = 1; //标记计算的位,个位十位。。。。。
int result = 0; //统计计算的结果
scanf("%d",&n);
Tn = n;
while(n) {
T = n%10 ;
if (T == 1) { // 当前位为1时
result += (n/10)*mul; // 先把高一位减1计算结果
result += (Tn%mul)+1; // 再计算低位的个数
} else if(T == 0) { //当前位为0,不需要+1
result += (n/10)*mul;
} else { // 当前为非0和1,正常计算
result += (n/10+1)*mul;
}
mul *= 10; //计算完之后,标记进一位
n /= 10; //整个数缩小用于判定
}
printf("%d",result);
return 0;
}