题目
题意
求 1 ∼ N 1 \thicksim N 1∼N 中 1 1 1 的个数
分析
设数字
N
N
N 共
k
k
k 位,第
i
i
i 位为数字
b
b
b 。其前面组成数字
a
a
a ,后面组成数字
c
c
c。
n
k
−
1
n
k
−
2
…
n
i
+
2
n
i
+
1
⏞
a
n
i
b
n
i
−
1
n
i
−
2
…
n
1
n
0
⎵
c
\overbrace{n_{k-1}\ n_{k-2}\dots\ n_{i+2}\ n_{i+1}}^{a}\ \overset{b}{n_i} \ \underbrace{n_{i-1}\ n_{i-2}\dots\ n_1\ n_0}_c
nk−1 nk−2… ni+2 ni+1
a nib c
ni−1 ni−2… n1 n0
因为
n
i
n_i
ni 的情况有3种:
- b > 1 b>1 b>1 ,则 b b b 前面数字的范围可以是 ( 0 , a ) (0,a) (0,a) 共 a + 1 a+1 a+1 个,由于 b > 1 b>1 b>1 则 b b b 之后的数字随意,选取范围为 ( 0 , 1 0 i − 1 ) (0,10^i-1) (0,10i−1),总共 ( a + 1 ) × 1 0 i (a+1)\times 10^i (a+1)×10i 种。
- b = 1 b=1 b=1 ,前面的范围比 c a s e 1 case1 case1 少一种,因为前面的数为 a a a 时后面的数只有 ( 0 , c ) (0,c) (0,c) 满足 b = 1 b=1 b=1,总共 a × 1 0 i + c + 1 a\times 10^i+c+1 a×10i+c+1种。
- b = 0 b=0 b=0,比 c a s e 1 case1 case1 前面范围完全少一种,故 a × 1 0 i a\times 10^i a×10i 种。
则
i
i
i 位为
1
1
1 的个数为
f
(
i
)
=
{
(
a
+
1
)
×
1
0
i
,
b
>
1
;
a
×
1
0
i
+
c
+
1
,
b
=
1
;
a
×
1
0
i
,
b
=
0.
f(i)=\begin{dcases} (a+1)\times 10^i,&b>1;\\ a\times 10^i+c+1,&b=1;\\ a\times 10^i,&b=0. \end{dcases}
f(i)=⎩⎪⎨⎪⎧(a+1)×10i,a×10i+c+1,a×10i,b>1;b=1;b=0.
累加即可
初次提交代码
#include<cstdio>
#include<cmath>
#pragma warning(disable:4996)
int main() {
int a, b, c = 0, ans = 0;
scanf("%d", &a);
for (int i = 0; a; i++) {//a为0退出
b = a % 10;
a /= 10;
if (b > 1) ans += (a + 1) * pow(10, i);
else if (b < 1) ans += a * pow(10, i);
else ans += a * pow(10, i) + c + 1;
c += b * pow(10, i);
}
printf("%d\n", ans);
return 0;
}
运行结果
2019/4/24 16:13:33 答案正确 30 1049 C++ (g++) 3 ms
测试点 结果 耗时 内存
0 答案正确 2 ms 384 KB
1 答案正确 2 ms 384 KB
2 答案正确 2 ms 296 KB
3 答案正确 3 ms 384 KB
4 答案正确 2 ms 384 KB
5 答案正确 2 ms 256 KB
6 答案正确 2 ms 256 KB
改进1
可以改用变量 k 来代替 pow(10,i) 同时可节省 i 的变量空间,for 改为 while。
#include<cstdio>
#pragma warning(disable:4996)
int main() {
int n,a, b, c, k = 1, ans = 0;
scanf("%d", &n);
while (n / k != 0) {
a = n / (k * 10);
b = n / k % 10;
c = n % k;
if (b > 1) ans += (a + 1) * k;
else if (b < 1) ans += a * k;
else ans += a * k + c + 1;
k *= 10;
}
printf("%d\n", ans);
return 0;
}
《算法笔记》P198-200. ↩︎