# NOI CSP-J 初赛专项模拟题:程序基本语句 ## 阅读程序 (程序输入不超过数组或字符串定义的范围,判断题正确填√,错误填×) ### (1) ```cpp 01 #include 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 的正整数,完成下面的判断题和单选题: **判断题** 1. 该程序的功能是计算 的值。( ) 2. 程序的输出结果一定是一个小于 10 的整数。( ) 3. 当输入为“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) ```cpp 01 #include 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) ```cpp 01 #include 02 #include 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)** ```cpp 01 #include 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 的正整数,完成下面的判断题和单选题: **判断题** 1. 当输入 x 为偶数时,函数 `f(x)` 只会进行递归调用,不会增加数值。( ) 2. 该函数一定会终止,不会出现死循环。( ) 3. 当输入 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)** ```cpp 01 #include 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 的正整数,完成下面的判断题和单选题: **判断题** 1. 该程序计算的是组合数学中杨辉三角或类似路径计数的问题。( ) 2. 如果输入 n=1, m=5,输出结果为 5。( ) 3. 无论输入什么正整数,数组 `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 不是。 ```cpp 01 #include 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 } ``` 16. ①处应填( ) A. 0 B. 1 C. n D. -1 17. ②处应填( ) A. t / 10 B. t % 10 C. n % 10 D. n / 10 18. ③处应填( ) A. t / 10 B. t % 10 C. t - 1 D. t + 1 19. ④处应填( ) A. n == t B. n == 0 C. n == y D. y == t 20. 如果输入的 `n` 是 `100`,循环结束后 `y` 的值是( ) A. 1 B. 0 C. 001 D. 10 ### (2) 最大公约数与最小公倍数 输入两个正整数 `m` 和 `n`,求它们的最大公约数 (GCD) 和最小公倍数 (LCM)。程序使用辗转相除法(欧几里得算法)的迭代实现。 ```cpp 01 #include 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 } ``` 21. ①处应填( ) A. m != 0 B. n != 0 C. r != 0 D. m % n == 0 22. ②处应填( ) A. n B. r C. a D. b 23. ③处应填( ) A. m B. r C. a D. b 24. ④处应填( ) A. n B. r C. m D. a 25. ⑤处应填( ) A. a * b / m B. a * b / n C. a * b / r D. m * n / a --- **(3) 高精度加法** 输入两个正整数(可能非常大,超过 `long long` 范围),输出它们的和。 程序使用字符串读取输入,然后转化为数组进行逐位计算。 ```cpp 01 #include 02 #include 03 #include 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 } ``` 26. ①处应填( ) A. `s1[i]` B. `s1[i] - '0'` C. `s1[len1 - 1 - i]` D. `s1[len1 - 1 - i] - '0'` 27. ②处应填( ) A. `c[i] % 10` B. `c[i] / 10` C. `c[i+1] + c[i] / 10` D. `a[i] + b[i]` 28. ③处应填( ) A. `c[i] / 10` B. `c[i] % 10` C. `a[i] % 10` D. `b[i] % 10` 29. ④处应填( ) A. `c[len] > 0` B. `c[len] >= 10` C. `c[len-1] > 0` D. `c[len] != 0` 30. ⑤处应填( ) A. `c[i]` B. `c[len - i]` C. `a[i] + b[i]` D. `c[i] + '0'` # 答案与解析 ## 阅读程序 ### (1) 1. **×** **解析:** 程序在循环中每次将 `ans` 乘以 `x` 后立即对 10 取模,因此它计算的是 的**个位数字**,而不是 的值。 2. **√** **解析:** 由于每次运算都执行 `% 10`,结果 `ans` 必定在 0 到 9 之间。 3. **√** **解析:** 输入 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。 ``` 4. **B** **解析:** 输入 12 2。 ``` i=1: ans = 1*12%10 = 12%10 = 2 i=2: ans = 2*12%10 = 24%10 = 4 输出 4。 ``` 5. **B** **解析:** 输入 2 10,计算 的个位数。 规律为 2,4,8,6 循环。10 % 4 = 2,所以是第 2 个,即 4。 ### (2) 6. **×** **解析:** 变量 `count` 累加的是 `a[i]` 的值(`count = count + a[i]`),而不是个数。它计算的是**大于0的偶数之和**。 7. **√** **解析:** 如果全是负数,`a[i] > 0` 条件始终不满足,`count` 保持初始值 0。 8. **×** **解析:** 如果去掉 `a[i] > 0`,负偶数也会被加进去,结果会改变。例如输入 -2,原程序加 0,去掉条件后加 -2。 9. **C** **解析:** 数组 1 2 3 4 5 中,大于0的偶数有 2, 4。和为 2+4=6。 10. **A** **解析:** 数组 -2 -4 2 4 6 中,大于0的偶数有 2, 4, 6。和为 2+4+6=12。 ### (3) 11. **×** **解析:** 程序只是修改字符的值(ASCII码变换),不涉及插入或删除,长度不变。 12. **√** **解析:** C, S, P 都是大写,满足第二个 `if`,加 32 变为小写 c, s, p。 13. **√** **解析:** 第一个 `if` 将小写转大写(-32),第二个 `if` 将大写转小写(+32)。 14. **C** **解析:** "Hello"。'H' 是大写 -> 'h'。'e','l','l','o' 是小写 -> 'E','L','L','O'。输出 "hELLO"。 15. **A** **解析:** `s[i] - 32` 等价于 `s[i] - ('a' - 'A')`,即 `s[i] - 'a' + 'A'`。这是标准的转换方式。 ## 完善程序 ### (1) 判断回文数 * **算法思路:** 将数字 `n` 翻转生成新数字 `y`,比较 `n` 和 `y` 是否相等。 * **解析:** 16. **C (n)**:需要用一个临时变量 `t` 来操作,保留原数 `n` 用于最后比较,所以 `t` 初始化为 `n`。 17. **B (t % 10)**:取出 `t` 的最后一位数字。 18. **A (t / 10)**:去掉 `t` 的最后一位数字,以便下一次循环取下一位。 19. **C (n == y)**:比较原数 `n` 和翻转后的数 `y`。 20. **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。 * **解析:** 21. **B (n != 0)**:循环继续的条件是除数不为 0。 22. **A (n)**:将原来的除数 `n` 赋值给被除数 `m`。 23. **B (r)**:将余数 `r` 赋值给除数 `n`。 24. **C (m)**:循环结束时 `n` 为 0,`m` 存储的是最大公约数。 25. **A (a * b / m)**:最小公倍数 = 两数之积 / 最大公约数。注意原数保存在 `a` 和 `b` 中,`m` 是计算出的 GCD。