【题目】
CSP-J 2022 入门级 第一轮 阅读程序(3) 第28-34题
阅读程序
01 #include <iostream>
02
03 using namespace std;
04
05 int n, k;
06
07 int solve1()
08 {
09 int l = 0, r = n;
10 while (l <= r) {
11 int mid = (l + r) / 2;
12 if (mid * mid <= n) l = mid + 1;
13 else r = mid - 1;
14 }
15 return l - 1;
16 }
17
18 double solve2(double x)
19 {
20 if (x == 0) return x;
21 for (int i = 0; i < k; i++)
22 x = (x + n / x) / 2;
23 return x;
24 }
25
26 int main()
27 {
28 cin >> n >> k;
29 double ans = solve2(solve1());
30 cout << ans << ' ' << (ans * ans == n) << endl;
31 return 0;
32 }
假设 int 为 32 位有符号整数类型,输入的 n 是不超过 47000 的自然数、 k 是不超过 int 表示范围的自然数,完成下面的判断题和单选题:
判断题
28. 该算法最准确的时间复杂度分析结果为 𝑂(log 𝑛 + 𝑘) 。( )
29. 当输入为“ 9801 1 ”时,输出的第一个数为“ 99 ”。( )
30. 对于任意输入的 n ,随着所输入 k 的增大,输出的第二个数会变成“ 1 ”。( )
31. 该程序有存在缺陷。当输入的 n 过大时,第 12 行的乘法有可能溢出,因此应当将mid 强制转换为 64 位整数再计算。( )
单选题
32. 当输入为“ 2 1 ”时,输出的第一个数最接近( )。
A. 1
B. 1.414
C. 1.5
D. 2
33. 当输入为“ 3 10 ”时,输出的第一个数最接近( )。
A. 1.7
B. 1.732
C. 1.75
D. 2
34. 当输入为“ 256 11 ”时,输出的第一个数( )。
A. 等于 16
B. 接近但小于 16
C. 接近但大于 16
D. 前三种情况都有可能
【题目考点】
1. 二分
【解题思路】
观察solve1函数,明显是二分答案算法。
满足mid*mid<=n
时,l=mid+1
取右半边。
最后取l-1,由于l都是mid+1,所以最后取到的是满足条件的mid。
可以看出,这个二份答案求的是:满足mid*mid<=n
条件的,mid的最大值。
实际就是求
⌊
n
⌋
\lfloor \sqrt{n} \rfloor
⌊n⌋
至于solve2函数,传入的x是:
⌊
n
⌋
\lfloor \sqrt{n} \rfloor
⌊n⌋,而当
n
\sqrt{n}
n不是整数时,
n
/
x
n/x
n/x是个略大于
n
\sqrt{n}
n的数字。
⌊
n
⌋
\lfloor \sqrt{n} \rfloor
⌊n⌋与n/x二者取平均数后的值赋值给x,x变得更接近
n
\sqrt{n}
n。
重复这一过程,会使x不断逼近
n
\sqrt{n}
n。
28. 该算法最准确的时间复杂度分析结果为
O
(
l
o
g
n
+
k
)
O(logn + k)
O(logn+k) 。( )
答:正确。solve1函数是二分算法,二分查找的范围为n,复杂度为
O
(
l
o
g
n
)
O(logn)
O(logn),solve1求出值后,把值传给solve2函数。sovle2函数里面只有k次循环,复杂度为
O
(
k
)
O(k)
O(k),所以整体复杂度为
O
(
l
o
g
n
+
k
)
O(logn+k)
O(logn+k)
29. 当输入为“ 9801 1 ”时,输出的第一个数为“ 99 ”。( )
答:正确。
sove1求出
⌊
n
⌋
=
⌊
9801
⌋
=
99
\lfloor \sqrt{n}\rfloor=\lfloor \sqrt{9801}\rfloor=99
⌊n⌋=⌊9801⌋=99
sove2中x=99,k为1,for循环执行一次,x=(x+n/x)/2=(99+9801/99)/2=99
输出ans为99。
30. 对于任意输入的 n ,随着所输入 k 的增大,输出的第二个数会变成“ 1 ”。( )
答:错误。
随着输入k的增大,输出的第二个数会接近或等于
n
\sqrt{n}
n
31. 该程序有存在缺陷。当输入的 n 过大时,第 12 行的乘法有可能溢出,因此应当将 mid 强制转换为 64 位整数再计算。( )
答:错误
题目限定了n最大是47000,第一次求出mid=n/2为23500,mid*mid为
2350
0
2
23500^2
235002=552250000,int类型可以表示该数字,并不会溢出。
(如果说n过大会超过题目限定的47000,那极端一点,当n特别大时,转为64位的long long类型计算仍然可能溢出。)
32. 当输入为“ 2 1 ”时,输出的第一个数最接近( )。
A. 1
B. 1.414
C. 1.5
D. 2
答:选C。
solve1传入2,求出结果为
⌊
2
⌋
=
1
\lfloor \sqrt{2} \rfloor = 1
⌊2⌋=1。
把1传入solve2,x为1,循环1次,x = (x+n/x)/2=(1+2/1)/2=1.5,函数的返回值,也就是ans的值为1.5
33. 当输入为“ 3 10 ”时,输出的第一个数最接近( )。
A. 1.7
B. 1.732
C. 1.75
D. 2
答:选B。
solve1传入3,求出结果为
⌊
3
⌋
=
1
\lfloor \sqrt{3} \rfloor = 1
⌊3⌋=1。
把1传入solve2,x为1,循环10次,,每次循环让x=(x+n/x)/2,用模拟运行法
k | x |
---|---|
0 | (1+3/1)/2=2 |
1 | (2+3/2)/2=1.75 |
2 | (1.75+3/1.75)/2=1.732 |
3 | (1.732+3/1.732)/2=1.732 |
后面不用算了,我们通过分析程序已知x最终会不断接近 3 \sqrt{3} 3的值,进行多次循环后,结果的前几位一定是1.732,不会改变。
34. 当输入为“ 256 11 ”时,输出的第一个数( )。
A. 等于 16
B. 接近但小于 16
C. 接近但大于 16
D. 前三种情况都有可能
答:选A。
solve1的结果为
⌊
256
⌋
=
16
\lfloor \sqrt{256} \rfloor=16
⌊256⌋=16,已知
256
=
16
\sqrt{256}=16
256=16,所以在solve2中x=(x+n/x)/2=(16+256/16)/2=16,每次计算后x的值不变,都是16。因此最后输出的值等于16。
【答案】
- 正确
- 正确
- 错误
- 错误
- C
- B
- A