#CSPJCSMN03. 普及组程序专项03
普及组程序专项03
初赛程序题专项(三)
二、阅读程序
(1)
01 #include <iostream>
02
03 using namespace std;
04
05 int countSetBits(int n) {
06 int count = 0;
07 while (n > 0) {
08 n &= (n - 1);
09 count++;
10 }
11 return count;
12 }
13
14 int main() {
15 int n, k;
16 cin >> n >> k;
17 int result = -1;
18 for (int i = 1; i <= n; ++i) {
19 if (countSetBits(i) == k) {
20 result = i;
21 break;
22 }
23 }
24 cout << result << endl;
25 return 0;
26 }
判断题
countSetBits(n)函数的功能是计算正整数n在二进制表示下1的个数。 ( )- 第 08 行的
n &= (n - 1)操作,其作用是清除n的二进制表示中最左边(最高位)的1。 ( ) countSetBits(n)函数的时间复杂度与n的二进制表示中1的数量成正比。 ( )
选择题
-
该程序旨在解决的问题是 ( )。
- A. 寻找
n的第k个约数 - B. 寻找
k的第n个倍数 - C. 寻找
1到n之间最小的、二进制表示恰好有k个1的整数 - D. 计算
1到n之间所有二进制表示恰好有k个1的整数的和
- A. 寻找
-
若输入为
100 3,则输出为 ( )。- A. 7
- B. 11
- C. 13
- D. 14
(2)
01 #include <iostream>
02 #include <vector>
03
04 using namespace std;
05
06 int n, m;
07 vector<vector<int>> dp;
08
09 int countPaths(int r, int c) {
10 if (r < 0 || c < 0) {
11 return 0;
12 }
13 if (r == 0 && c == 0) {
14 return 1;
15 }
16 if (dp[r][c] != -1) {
17 return dp[r][c];
18 }
19 dp[r][c] = countPaths(r - 1, c) + countPaths(r, c - 1);
20 return dp[r][c];
21 }
22
23 int main() {
24 cin >> n >> m;
25 dp.assign(n, vector<int>(m, -1));
26 cout << countPaths(n - 1, m - 1) << endl;
27 return 0;
28 }
判断题
- 该程序使用递归和记忆化的方法解决了问题。 ( )
dp[r][c]的值等于组合数 C(r+c, r)(即从 r+c 个物品中选 r 个的方案数)。 ( )- 如果将第 19 行
dp[r][c] = countPaths(r - 1, c) + countPaths(r, c - 1);改为dp[r][c] = countPaths(n - 2, m - 1) + countPaths(n - 1, m - 2);,程序的功能不变。 ( )
选择题
-
该程序解决的问题是 ( )。
- A. 在
n x m棋盘上从左上角走到右下角的最短路径长度 - B. 在
n x m棋盘上放置k个互不攻击的象的方法数 - C. 在
n x m棋盘上从左上角走到右下角,每次只能向右或向下走的路径总数 - D.
n个球放入m个盒子的总方案数
- A. 在
-
若输入为
4 3,则输出为 ( )。- A. 10
- B. 12
- C. 15
- D. 20
(3)
01 #include <iostream>
02 #include <vector>
03 #include <string>
04 #include <numeric>
05 #include <algorithm>
06
07 using namespace std;
08
09 int main() {
10 int n, k;
11 cin >> n >> k;
12 k--;
13
14 vector<char> chars;
15 for (int i = 0; i < n; ++i) {
16 chars.push_back('A' + i);
17 }
18
19 vector<long long> fact(n + 1, 1);
20 for (int i = 2; i <= n; ++i) {
21 fact[i] = fact[i - 1] * i;
22 }
23
24 string result = "";
25 for (int i = n; i >= 1; --i) {
26 int index = k / fact[i - 1];
27 result += chars[index];
28 chars.erase(chars.begin() + index);
29 k %= fact[i - 1];
30 }
31
32 cout << result << endl;
33 return 0;
34 }
判断题
- 该程序预计算了阶乘,是为了进行组合数的计算。 ( )
- 第 28 行
chars.erase(...)操作是程序能够正确运行的关键一步,它确保了每个字符只被使用一次。 ( ) - 若输入
n极大,k也极大,程序可能因为第 21 行的阶乘计算而发生整数溢出,导致错误结果。 ( )
选择题
-
该程序的功能是 ( )。
- A. 生成杨辉三角的第
n行第k列 - B. 求解
n个字符的字符串中长度为k的子序列个数 - C. 生成由前
n个大写字母构成的第k个字典序排列 - D. 将整数
k转换为n进制表示
- A. 生成杨辉三角的第
-
若输入为
4 10,则输出为 ( )。- A. "BADC"
- B. "BCDA"
- C. "CADB"
- D. "BDCA"
三、完善程序
(1) 统计岛屿数量
题目描述: 给定一个由 '1' (陆地) 和 '0' (水) 组成的 m x n 的二维网格,计算岛屿的数量。一个岛屿被水包围,并通过水平或垂直方向上相邻的陆地连接形成。你可以假设网格的四个边均被水包围。
01 #include <iostream>
02 #include <vector>
03 #include <queue>
04
05 using namespace std;
06
07 void bfs(int r, int c, int m, int n, vector<vector<char>>& grid) {
08 queue<pair<int, int>> q;
09 q.push({r, c});
10 ①;
11 int dr[] = {-1, 1, 0, 0};
12 int dc[] = {0, 0, -1, 1};
13
14 while (②) {
15 pair<int, int> curr = q.front();
16 q.pop();
17
18 for (int i = 0; i < 4; ++i) {
19 int nr = curr.first + dr[i];
20 int nc = curr.second + dc[i];
21
22 if (③ && grid[nr][nc] == '1') {
23 ④;
24 q.push({nr, nc});
25 }
26 }
27 }
28 }
29
30 int main() {
31
32 int m, n;
33 cin >> m >> n;
34 vector<vector<char>> grid(m, vector<char>(n));
35 for(int i=0; i<m; ++i) for(int j=0; j<n; ++j) cin >> grid[i][j];
36
37 int count = 0;
38 for (int i = 0; i < m; ++i) {
39 for (int j = 0; j < n; ++j) {
40 if (grid[i][j] == '1') {
41 count++;
42 ⑤(i, j, m, n, grid);
43 }
44 }
45 }
46 cout << count << endl;
47 return 0;
48 }
-
①处应填 ( ),用于标记起点已被访问。
- A.
grid[r][c] = '0' - B.
q.pop() - C.
return - D.
count++
- A.
-
②处应填 ( ),作为广度优先搜索的循环条件。
- A.
!q.empty() - B.
q.size() < m*n - C.
q.front().first < m - D.
true
- A.
-
③处应填 ( ),用于检查新坐标是否越界。
- A.
nr >= 0 && nr < m && nc >= 0 && nc < n - B.
nr > 0 || nr < m || nc > 0 || nc < n - C.
nr != r && nc != c - D.
grid[nr][nc] != '0'
- A.
-
④处应填 ( ),用于标记新发现的陆地已被访问。
- A.
grid[nr][nc] = grid[r][c] - B.
grid[nr][nc] = '1' - C.
grid[nr][nc] = '0' - D.
continue
- A.
-
⑤处应填 ( ),用于淹没整个岛屿。
- A.
main - B.
countIslands - C.
dfs - D.
bfs
- A.
(2) 互质数对统计
题目描述: 给定一个正整数 n,统计满足 1 <= i < j <= n 且 gcd(i, j) = 1 的数对 (i, j) 的数量。gcd(a, b) 指 a 和 b 的最大公约数。
01 #include <iostream>
02
03 using namespace std;
04
05 int gcd(int a, int b) {
06 if (b == 0) {
07 return ①;
08 }
09 return ②;
10 }
11
12 int main() {
13 int n;
14 cin >> n;
15 int count = 0;
16 for (int i = 1; i <= n; ++i) {
17 for (int j = ③; j <= n; ++j) {
18 if (④ == 1) {
19 count++;
20 }
21 }
22 }
23 cout << count << endl;
24 return 0;
25 }
-
①处是辗转相除法(欧几里得算法)的递归基例,应填 ( )。
- A.
0 - B.
1 - C.
a - D.
b
- A.
-
②处是算法的递归步骤,应填 ( )。
- A.
gcd(b, a) - B.
gcd(a, a % b) - C.
gcd(b, a - b) - D.
gcd(b, a % b)
- A.
-
③处是内层循环的起始条件,根据题目要求
i < j,应填 ( )。- A.
1 - B.
i - C.
i + 1 - D.
n
- A.
-
④处应调用函数来判断是否互质,应填 ( )。
- A.
gcd(i, j) - B.
count - C.
gcd(n, i) - D.
gcd(n, j)
- A.