CSP-S 2022 提高级 第一轮 阅读程序(3)

【题目】

CSP-S 2022 提高级 第一轮 阅读程序(3)

1  #include <iostream>
2  #include <algorithm>
3  
4  using namespace std;
5  
6  const int MAXL = 1000;
7  
8  int n, k, ans[MAXL];
9  
10 int main(void) 
11 {
12     cin >> n >> k;
13     if (!n) cout << 0 << endl;
14     else 
15     {
16         int m = 0;
17         while (n) 
18         {
19             ans[m++] = (n % (-k) + k) % k;
20             n = (ans[m - 1] - n) / k;
21         }
22         for (int i = m - 1; i >= 0; i--)
23             cout << char(ans[i] >= 10 ?
24                          ans[i] + 'A' - 10 :
25                          ans[i] + '0');
26         cout << endl;
27     }
28     return 0;
29 }

假设输入的 n 在 int 范围内,k 为不小于 2 且不大于 36 的正整数,完成下面的判断题和单选题:

判断题
1.该算法的时间复杂度为 O ( log ⁡ k n ) O(\log_k n) O(logkn)
2.删除第 23 行的强制类型转换,程序的行为不变。
3.除非输入的 n 为 0,否则程序输出的字符数为 O ( ⌊ log ⁡ k ∣ n ∣ ⌋ + 1 ) O(\lfloor \log_k|n|\rfloor+1) O(⌊logkn+1)
(注:洛谷上此处的题不对,原卷纸上是 O ( ⌊ log ⁡ k ∣ n ∣ ⌋ + 1 ) O(\lfloor \log_k|n|\rfloor+1) O(⌊logkn+1)
试卷截图:
在这里插入图片描述

单选题
4.当输入为“100 7”时,输出为( )。
A. 202
B. 1515
C. 244
D. 1754

5.当输入为“-255 8”时,输出为( )。
A. 1400
B. 1401
C. 417
D. 400

6.当输入为“1000000 19”时,输出为( )。
A. BG939
B. 87GIB
C. 1CD428
D. 7CF1B

【题目考点】

1. 数学取模

数学取模相关概念
证明:C++中取模运算为 % \% %,一定有 a % b a\%b a%b等于 a % ( − b ) a\%(-b) a%(b)
已知C++中除法运算的商为向0取整,设a除以b的商向0取整后为q。
所以有 a = q ∗ b + r a = q*b+r a=qb+r,其中r为 a % b a\%b a%b
设a除以b的实数商为c,c向零取整为q。
则a除以-b的实数商为-c,-c和c是相反数,相反数向零取整的结果也互为相反数,所以-c向零取整为-q。
根据 a = q ∗ b + r a = q*b+r a=qb+r a = ( − q ) ∗ ( − b ) + r a = (-q)*(-b)+r a=(q)(b)+r
其中-q是a除以-b向零取整的结果,r即为 a % ( − b ) a\%(-b) a%(b)
所以 a % b a\%b a%b等于 a % ( − b ) a\%(-b) a%(b)

【解题思路】

10 int main(void) 
11 {
12     cin >> n >> k;
13     if (!n) cout << 0 << endl;
14     else 
15     {
16         int m = 0;
17         while (n) 
18         {
19             ans[m++] = (n % (-k) + k) % k;
20             n = (ans[m - 1] - n) / k;
21         }
22         for (int i = m - 1; i >= 0; i--)
23             cout << char(ans[i] >= 10 ?
24                          ans[i] + 'A' - 10 :
25                          ans[i] + '0');
26         cout << endl;
27     }
28     return 0;
29 }

输入n和k,n为0时就输出0。
只要n不为0就进行循环。
ans[m++]=(n%(-k)+k) ,结合m初值为0,可以看出这是在做数组填充,填充的数在ans数组中的下标范围是0~m-1。
首先n%(-k)等于n%k(见【题目考点】)。
题目给定k是正整数,而(n%k+k)%k,就是在求数学取模 n   m o d   k n\ mod\ k n mod k的结果(见数学取模相关概念
所以这一句的意义是:将 n   m o d   k n\ mod\ k n mod k填充到ans数组中。
下一句n=(ans[m-1]-n)/k;,可以转为n=-(n-ans[m-1])/k;
ans[m-1]就是上一次填充到数组中的 n   m o d   k n\ mod\ k n mod k,根据除法定理,一定有商q满足 n = k ∗ q + ( n   m o d   k ) n=k*q+(n\ mod\ k) n=kq+(n mod k),q是 ⌊ n k ⌋ \lfloor \frac{n}{k} \rfloor kn。那么 ( n − ( n   m o d   k ) ) / k (n - (n\ mod\ k))/k (n(n mod k))/k就是q,即 ⌊ n k ⌋ \lfloor \frac{n}{k} \rfloor kn
所以n=(ans[m-1]-n)/k;所做的运算为把n变为 − ⌊ n k ⌋ -\lfloor \frac{n}{k} \rfloor kn
以上过程是将n在k进制下进行数位分离,但是每分离出一位后,该数值的符号取反。将分离出的各个数位填入ans数组中。其中较小下标保存低位数字,较大下标保存高位数字。
而后从高位到低位遍历,输出分离出的各个数字,对于大于等于10的数字,将其转为大写字母输出,其中’A’表示10,'B’表示11,……,'Z’表示35。

【试题答案及解析】

判断题
1.该算法的时间复杂度为 O ( log ⁡ k n ) O(\log_k n) O(logkn)
答:T
m是数值是n在k进制下的位数,其值 m = ⌊ log ⁡ k n ⌋ + 1 m=\lfloor \log_k n\rfloor+1 m=logkn+1。17行的while循环和22行的for循环的循环次数都是m次。总体时间复杂度为 O ( m ) = O ( log ⁡ k n ) O(m)=O(\log_k n) O(m)=O(logkn)
2.删除第 23 行的强制类型转换,程序的行为不变。
答:F
由于ans数组为int类型,int类型和char类型量进行运算的表达式的类型也是int类型。因此ans[i]+'A'-10ans[i]+'0'的值都是int类型。整个三目运算表达式ans[i]>=10 ? ans[i]+'A'-10 : ans[i]+'0'的值的类型也是int类型。
cout输出int类型的值,会输出整数,不会输出字符。强转char类型后,用cout输出可以输出字符。因此去掉强转char类型后,输出会改变。

3.除非输入的 n 为 0,否则程序输出的字符数为 O ( ⌊ log ⁡ k ∣ n ∣ ⌋ + 1 ) O(\lfloor \log_k|n|\rfloor+1) O(⌊logkn+1)
答:T
首先,根据大O表示法的计算规则,有: O ( ⌊ log ⁡ k ∣ n ∣ ⌋ + 1 ) = O ( l o g ∣ n ∣ ) O(\lfloor \log_k|n|\rfloor+1)=O(log|n|) O(⌊logkn+1)=O(logn)
每次循环输出一个字符,每次n的变化为 n = − ⌊ n k ⌋ n=-\lfloor \frac{n}{k} \rfloor n=kn
如果 n = ⌊ n k ⌋ n=\lfloor \frac{n}{k} \rfloor n=kn,该操作执行的次数就是n的位数,根据n在k进制下的位数公式,以及对数运算中真数必须大于0,该数字的位数,也就是循环次数应该为: ⌊ log ⁡ k ∣ n ∣ ⌋ + 1 \lfloor \log_k |n|\rfloor+1 logkn+1
而该问题中 n = − ⌊ n k ⌋ n=-\lfloor \frac{n}{k} \rfloor n=kn。考虑n的绝对值的变化,以下是定性分析:
n为正数时, ∣ n ∣ |n| n变为 ⌊ ∣ n ∣ k ⌋ \lfloor \frac{|n|}{k} \rfloor kn
n为负数时, ∣ n ∣ |n| n最大可以变为 ⌊ ∣ n ∣ k ⌋ + 1 \lfloor \frac{|n|}{k} \rfloor+1 kn+1
∣ n ∣ ≥ 2 , k ≥ 2 |n|\ge 2,k\ge 2 n2k2时,可以认为 ⌊ ∣ n ∣ k ⌋ + 1 ≤ ∣ n ∣ \lfloor \frac{|n|}{k} \rfloor+1\le |n| kn+1n
由于n的符号每次循环都会编号,因此可以保证至少每2次循环后 ∣ n ∣ |n| n会小于等于 ⌊ ∣ n ∣ k ⌋ \lfloor \frac{|n|}{k} \rfloor kn,当 ∣ n ∣ |n| n为0时跳出循环。该问题的循环次数不会超过 n = ⌊ n k ⌋ n=\lfloor \frac{n}{k} \rfloor n=kn问题的循环次数的2倍,也就是 2 ( ⌊ log ⁡ k ∣ n ∣ ⌋ + 1 ) 2(\lfloor \log_k |n|\rfloor+1) 2(⌊logkn+1) O ( 2 ( ⌊ log ⁡ k ∣ n ∣ ⌋ + 1 ) ) = O ( l o g ∣ n ∣ ) O(2(\lfloor \log_k |n|\rfloor+1)) = O(log|n|) O(2(⌊logkn+1))=O(logn)

单选题
4.当输入为“100 7”时,输出为( )。
A. 202
B. 1515
C. 244
D. 1754

答:A
该问题的计算方法为:每次取 n   m o d   k n\ mod\ k n mod k,而后n变为n除以k的商并将符号取反,将取出的数字从后向前排列,即为结果。
其中mod运算为数学取模,即为求n/k的商向下取整时的余数,保证余数为非负整数。

除法式余数
100/7142
-14/7-20
2/702

5.当输入为“-255 8”时,输出为( )。
A. 1400
B. 1401
C. 417
D. 400

答:B

除法式余数
-255/8-321
32/840
-4/8-14
1/801

结果为1401
6.当输入为“1000000 19”时,输出为( )。
A. BG939
B. 87GIB
C. 1CD428
D. 7CF1B

答:B

除法式余数
1000000/195263111(B)
-52631/19277118(I)

算出最后两位就能确定答案是B。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值