11 KiB
NOI CSP-J 初赛专项模拟题:程序基本语句
阅读程序 (程序输入不超过数组或字符串定义的范围,判断题正确填√,错误填×)
(1)
01 #include <iostream>
02 using namespace std;
03
04 int main() {
05 int x, y;
06 cin >> x >> y;
07 int ans = 1;
08 for (int i = 1; i <= y; i++) {
09 ans = ans * x;
10 ans = ans % 10;
11 }
12 cout << ans << endl;
13 return 0;
14 }
假设输入的 x, y 均为不超过 100 的正整数,完成下面的判断题和单选题:
判断题
- 该程序的功能是计算 的值。( )
- 程序的输出结果一定是一个小于 10 的整数。( )
- 当输入为“2 3”时,输出为“8”。( )
单选题 4. 当输入为“12 2”时,输出为( )。 A. 2 B. 4 C. 24 D. 144 5. 当输入为“2 10”时,输出为( )。 A. 2 B. 4 C. 6 D. 8
(2)
01 #include <iostream>
02 using namespace std;
03
04 int main() {
05 int n;
06 cin >> n;
07 int a[105];
08 for(int i = 1; i <= n; i++) {
09 cin >> a[i];
10 }
11 int count = 0;
12 for(int i = 1; i <= n; i++) {
13 if(a[i] > 0 && a[i] % 2 == 0) {
14 count = count + a[i];
15 }
16 }
17 cout << count << endl;
18 return 0;
19 }
假设输入的 n 为不超过 100 的正整数,数组元素均为 int 范围内整数,完成下面的判断题和单选题:
判断题
6. 该程序统计的是数组中所有偶数的个数。( )
7. 如果数组中所有的数都是负数,输出结果为 0。( )
8. 第 13 行的 a[i] > 0 条件如果去掉,程序的输出结果对于任何输入都不会改变。( )
单选题
9. 当输入 n=5,数组元素为 1 2 3 4 5 时,输出为( )。
A. 2 B. 3 C. 6 D. 9
10. 当输入 n=5,数组元素为 -2 -4 2 4 6 时,输出为( )。
A. 12 B. 6 C. 0 D. -6
(3)
01 #include <iostream>
02 #include <string>
03 using namespace std;
04
05 int main() {
06 string s;
07 cin >> s;
08 int len = s.length();
09 for (int i = 0; i < len; i++) {
10 if (s[i] >= 'a' && s[i] <= 'z') {
11 s[i] = s[i] - 32;
12 } else if (s[i] >= 'A' && s[i] <= 'Z') {
13 s[i] = s[i] + 32;
14 }
15 }
16 cout << s << endl;
17 return 0;
18 }
假设输入仅包含英文字母,完成下面的判断题和单选题:
判断题
11. 程序执行后,字符串 s 的长度可能会发生改变。( )
12. 输入 "CSP" 时,输出 "csp"。( )
13. 该程序实现了大小写字母互换的功能。( )
单选题
14. 当输入 "Hello" 时,输出为( )。
A. hello B. HELLO C. hELLO D. Hello
15. 已知 'a' 的 ASCII 码是 97,'A' 的 ASCII 码是 65,则第 11 行可以改为 s[i] = s[i] - 'a' + 'A',效果不变。该说法( )。
A. 正确 B. 错误 C. 编译错误 D. 运行时错误
(4)
01 #include <iostream>
02 using namespace std;
03
04 int f(int n) {
05 if (n <= 1) return 1;
06 if (n % 2 == 0)
07 return f(n / 2) + n;
08 else
09 return f(n - 1) + 1;
10 }
11
12 int main() {
13 int x;
14 cin >> x;
15 cout << f(x) << endl;
16 return 0;
17 }
假设输入的 x 为不超过 1000 的正整数,完成下面的判断题和单选题:
判断题
- 当输入 x 为偶数时,函数
f(x)只会进行递归调用,不会增加数值。( ) - 该函数一定会终止,不会出现死循环。( )
- 当输入 5 时,输出结果为 6。( )
单选题
4. 当输入 8 时,输出为( )。
A. 13 B. 14 C. 15 D. 16
5. 当输入 10 时,函数 f 被调用的次数(包括 main 中的第一次调用)是( )。
A. 4 B. 5 C. 6 D. 7
(5)
01 #include <iostream>
02 using namespace std;
03
04 int main() {
05 int n, m;
06 cin >> n >> m;
07 int a[20][20];
08 for (int i = 0; i < n; i++) {
09 for (int j = 0; j < m; j++) {
10 if (i == 0 || j == 0)
11 a[i][j] = 1;
12 else
13 a[i][j] = a[i - 1][j] + a[i][j - 1];
14 }
15 }
16 cout << a[n - 1][m - 1] << endl;
17 return 0;
18 }
假设输入的 n, m 均为不超过 15 的正整数,完成下面的判断题和单选题:
判断题
- 该程序计算的是组合数学中杨辉三角或类似路径计数的问题。( )
- 如果输入 n=1, m=5,输出结果为 5。( )
- 无论输入什么正整数,数组
a中的值都会随i和j的增大而单调递增(不考虑边界)。( )
单选题 4. 当输入 3 3 时,输出为( )。 A. 4 B. 5 C. 6 D. 10 5. 该程序模拟的计算过程等价于求解从网格左上角 (0,0) 走到右下角 (n-1, m-1) 的路径数,且每次只能向右或向下走。如果输入 4 3,输出结果为( )。 A. 6 B. 10 C. 15 D. 20
三、完善程序 (单选题)
(1) 判断回文数
读入一个正整数 n,判断它是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都一样的整数,例如 121 是回文数,而 123 不是。
01 #include <iostream>
02 using namespace std;
03
04 int main() {
05 int n, t, y = 0;
06 cin >> n;
07 t = ①;
08 while (t > 0) {
09 y = y * 10 + ②;
10 t = ③;
11 }
12 if (④)
13 cout << "Yes" << endl;
14 else
15 cout << "No" << endl;
16 return 0;
17 }
- ①处应填( ) A. 0 B. 1 C. n D. -1
- ②处应填( ) A. t / 10 B. t % 10 C. n % 10 D. n / 10
- ③处应填( ) A. t / 10 B. t % 10 C. t - 1 D. t + 1
- ④处应填( ) A. n == t B. n == 0 C. n == y D. y == t
- 如果输入的
n是100,循环结束后y的值是( ) A. 1 B. 0 C. 001 D. 10
(2) 最大公约数与最小公倍数
输入两个正整数 m 和 n,求它们的最大公约数 (GCD) 和最小公倍数 (LCM)。程序使用辗转相除法(欧几里得算法)的迭代实现。
01 #include <iostream>
02 using namespace std;
03
04 int main() {
05 int m, n, a, b, r;
06 cin >> m >> n;
07 a = m;
08 b = n;
09 while (①) {
10 r = m % n;
11 m = ②;
12 n = ③;
13 }
14 cout << "GCD: " << ④ << endl;
15 cout << "LCM: " << ⑤ << endl;
16 return 0;
17 }
- ①处应填( ) A. m != 0 B. n != 0 C. r != 0 D. m % n == 0
- ②处应填( ) A. n B. r C. a D. b
- ③处应填( ) A. m B. r C. a D. b
- ④处应填( ) A. n B. r C. m D. a
- ⑤处应填( ) A. a * b / m B. a * b / n C. a * b / r D. m * n / a
(3) 高精度加法
输入两个正整数(可能非常大,超过 long long 范围),输出它们的和。
程序使用字符串读取输入,然后转化为数组进行逐位计算。
01 #include <iostream>
02 #include <string>
03 #include <algorithm>
04 using namespace std;
05
06 int a[505], b[505], c[505];
07
08 int main() {
09 string s1, s2;
10 cin >> s1 >> s2;
11 int len1 = s1.length();
12 int len2 = s2.length();
13
14 for (int i = 0; i < len1; i++) a[len1 - 1 - i] = ①;
15 for (int i = 0; i < len2; i++) b[len2 - 1 - i] = s2[i] - '0';
16
17 int len = len1 > len2 ? len1 : len2;
18 for (int i = 0; i < len; i++) {
19 c[i] += a[i] + b[i];
20 c[i + 1] = ②;
21 c[i] = ③;
22 }
23
24 if (④) len++;
25
26 for (int i = len - 1; i >= 0; i--) {
27 cout << ⑤;
28 }
29 cout << endl;
30 return 0;
31 }
- ①处应填( )
A.
s1[i]B.s1[i] - '0'C.s1[len1 - 1 - i]D.s1[len1 - 1 - i] - '0' - ②处应填( )
A.
c[i] % 10B.c[i] / 10C.c[i+1] + c[i] / 10D.a[i] + b[i] - ③处应填( )
A.
c[i] / 10B.c[i] % 10C.a[i] % 10D.b[i] % 10 - ④处应填( )
A.
c[len] > 0B.c[len] >= 10C.c[len-1] > 0D.c[len] != 0 - ⑤处应填( )
A.
c[i]B.c[len - i]C.a[i] + b[i]D.c[i] + '0'
答案与解析
阅读程序
(1)
- ×
解析: 程序在循环中每次将
ans乘以x后立即对 10 取模,因此它计算的是 的个位数字,而不是 的值。 - √
解析: 由于每次运算都执行
% 10,结果ans必定在 0 到 9 之间。 - √ 解析: 输入 2 3,循环执行 3 次。
i=1: ans = 1*2%10 = 2
i=2: ans = 2*2%10 = 4
i=3: ans = 4*2%10 = 8
输出 8。
- B 解析: 输入 12 2。
i=1: ans = 1*12%10 = 12%10 = 2
i=2: ans = 2*12%10 = 24%10 = 4
输出 4。
- B 解析: 输入 2 10,计算 的个位数。 规律为 2,4,8,6 循环。10 % 4 = 2,所以是第 2 个,即 4。
(2)
- ×
解析: 变量
count累加的是a[i]的值(count = count + a[i]),而不是个数。它计算的是大于0的偶数之和。 - √
解析: 如果全是负数,
a[i] > 0条件始终不满足,count保持初始值 0。 - ×
解析: 如果去掉
a[i] > 0,负偶数也会被加进去,结果会改变。例如输入 -2,原程序加 0,去掉条件后加 -2。 - C 解析: 数组 1 2 3 4 5 中,大于0的偶数有 2, 4。和为 2+4=6。
- A 解析: 数组 -2 -4 2 4 6 中,大于0的偶数有 2, 4, 6。和为 2+4+6=12。
(3)
- × 解析: 程序只是修改字符的值(ASCII码变换),不涉及插入或删除,长度不变。
- √
解析: C, S, P 都是大写,满足第二个
if,加 32 变为小写 c, s, p。 - √
解析: 第一个
if将小写转大写(-32),第二个if将大写转小写(+32)。 - C 解析: "Hello"。'H' 是大写 -> 'h'。'e','l','l','o' 是小写 -> 'E','L','L','O'。输出 "hELLO"。
- A
解析:
s[i] - 32等价于s[i] - ('a' - 'A'),即s[i] - 'a' + 'A'。这是标准的转换方式。
完善程序
(1) 判断回文数
- 算法思路: 将数字
n翻转生成新数字y,比较n和y是否相等。 - 解析:
- C (n):需要用一个临时变量
t来操作,保留原数n用于最后比较,所以t初始化为n。 - B (t % 10):取出
t的最后一位数字。 - A (t / 10):去掉
t的最后一位数字,以便下一次循环取下一位。 - C (n == y):比较原数
n和翻转后的数y。 - A (1):
n=100。 第一次:y=0+0=0,t=10第二次:y=0+0=0,t=1第三次:y=0+1=1,t=0循环结束,y为 1。
(2) 最大公约数与最小公倍数
- 算法思路: 欧几里得算法:
gcd(m, n) = gcd(n, m % n),直到n为 0,此时m即为 GCD。LCM = (a * b) / GCD。 - 解析:
- B (n != 0):循环继续的条件是除数不为 0。
- A (n):将原来的除数
n赋值给被除数m。 - B (r):将余数
r赋值给除数n。 - C (m):循环结束时
n为 0,m存储的是最大公约数。 - A (a * b / m):最小公倍数 = 两数之积 / 最大公约数。注意原数保存在
a和b中,m是计算出的 GCD。