1049 Counting Ones (30point(s))
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 (≤230).
Output Specification:
For each test case, print the number of 1's in one line.
Sample Input:
12
Sample Output:
5
思路:
可以把问题转化为排列组合问题:正整数N是一个n位十进制数,假设现在有n个盒子,编号分别位1,2,3,... n,分别对应个位、十位、百位、、。而现在我们需要把数字0~9分别放到n个盒子中,要满足放进盒子后,组成的数小于等于N,问有多少种放法
用排列的思想来考虑问题
假设N=30710,有5个盒子
5号 | 4号 | 3号 | 2号 | 1号 |
3 | 0 | 7 | 1 | 0 |
1⃣️ 1号盒子的数是1时,要让盒子组成的数<=N,
由于1号盒子的数是1,30710的1号位时0,1>0,那么2号~5号可以取 0000~3070,共3071种情况(因为1号盒子存放的是1,如果2~5号取3071,那么盒子组成的数就是30711>N,不符合,所以最多是3070)
2⃣️ 2号盒子的数是1时,要让盒子组成的数<=N,
由于2号盒子的数是1,30710的1号位时1,1==1,那么3号~5号取000~306时,共307种情况,1号可以取0~9共10^1种情况,所以一共有307*10=3070种取法
3号~5号 等于307时,1号只能取0,即30710
总共3070+1=3071种
3⃣️ 3号盒子的数是1时,要让盒子组成的数<=N,
由于3号盒子的数1,30710的4号位是7,而1<7,所以4号~5号盒子可以取 00~30共31种,1号~2号可以取00~99共10^2=100种情况,共31*100=3100种
4⃣️ 4号盒子的数是1时,要让盒子组成的数<=N,
由于4号时数时1,30710的4号位是0,而1>0,所以5号位可以取0~2共3种,1~3号位可以取000~999共10^3=1000种,共3*1000=3000种(5号盒子的数不能>2,否则组成的数>N)
总共有 3000种
5⃣️ 5号盒子的数是1时,要让盒子组成的数<=N,
由于5号盒子时1,30710的5号位时3,而1<3,所以1~4号位可以取 0000~9999共10^4=10000个数
所以把1放在1~5号盒子,共有3071+3071+3100+3000+10000=22242种情况,即共有22242个‘1’
由上面的红色字体可知,
(下面 k为i号右边的位数)
当N的第i号位>1时候,共有 (i号左边的数的可取个数)* (),
当N的第i号为=1时候,共有 (i号左边的数的可取个数) * () + ( i号右边的数的可取个数)
当N的第i号位<1时候,共有 (i号左边的数的可取个数) * ()
假设N的i号位左边的数为 left,右边的数为 right,中间的数为 now
now>1时,(left+1)* ()
now=1时,(left)* () + (right+1)
now<1时,(left)* ()
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<string>
#include<functional>
#include<sstream>
using namespace std;
typedef long long ll;
int main() {
int n, p, len;
int left, right, now;
scanf("%d", &n);
len = to_string(n).size();
ll ans = 0;
p = 1; // p = 10^k
for (int i = 1; i <= len; i++) {
right = n%p; // i号位右边的数
now = (n / p) % 10; //i号位的数
left = n / (p * 10);//i号位左边的数
if (now > 1) {
ans += (left + 1)*p;
}
else if (now == 1) {
ans += left*p + right + 1;
}
else {
ans += left*p;
}
p *= 10;
}
printf("%lld\n", ans);
return 0;
}