CSP 历年真题精讲 · 2025 CSP-J 入门级(上)
2025 年 CSP-J 入门级复赛
考试时间:2025 年 11 月 1 日 · 满分 400 · 时长 3.5 小时
题一:拼数(number)
【题目描述】
小 R 正在学习字符串处理。小 X 给了小 R 一个字符串 s,其中 s 仅包含小写英文字母及数字,且包含至少一个 1~9 中的数字。
小 X 希望小 R 使用 s 中的任意多个数字,按任意顺序拼成一个正整数。注意:小 R 可以选择 s 中的数字,但每个数字只能使用一次。
例如,若 s 为 1a01b,则小 R 可以同时选择第 1、3、4 个字符,分别为 1、0、1,拼成正整数 101 或 110;但小 R 不能拼成正整数 111,因为 s 仅包含两个数字 1。
小 R 想知道,在他所有能拼成的正整数中,最大的是多少。你需要帮助小 R 求出他能拼成的正整数的最大值。
【输入格式】
输入的第一行包含一个字符串 s,表示小 X 给小 R 的字符串。
【输出格式】
输出一行一个正整数,表示小 R 能拼成的正整数的最大值。
【样例】
样例 1 输入:
5
样例 1 输出:
5
样例 1 解释: s 仅包含一个数字 5,因此小 R 仅能拼成正整数 5。
样例 2 输入:
290es1q0
样例 2 输出:
92100
样例 2 解释: s 包含数字 2, 9, 0, 1, 0。可以证明,小 R 拼成的正整数的最大值为 92100。
【数据范围】
设 |s| 为字符串 s 的长度。对于所有测试数据,保证:
1 ≤ |s| ≤ 10⁶ s 仅包含小写英文字母及数字,且包含至少一个 1~9 中的数字
| 特殊性质 | 说明 |
|---|---|
| 性质 A | s 仅包含数字 |
| 性质 B | s 仅包含不超过 10³ 个数字 |
【解题思路】
这是一道非常简单的计数排序题,属于签到题级别。
核心思路:
遍历字符串 s,提取所有数字字符( '0'~'9')要拼出最大的正整数,显然应该把大的数字放前面,小的放后面 由于数字只有 0~9十种,可以使用计数排序(桶排序):开一个大小为 10 的数组 cnt[10],统计每个数字出现的次数从 9到0依次输出对应次数个该数字
时间复杂度:O(|s|),非常高效。
注意:字符串长度可达 10⁶,不要使用 s.erase() 或反复拼接字符串,直接输出即可。
【参考代码(C++)】
#include <bits/stdc++.h>
using namespace std;
char s[1000005];
int cnt[10]; // 统计每种数字出现的次数
int main() {
cin >> s;
int n = strlen(s);
for (int i = 0; i < n; i++) {
if (s[i] >= '0' && s[i] <= '9') {
cnt[s[i] - '0']++;
}
}
// 从大到小输出
for (int d = 9; d >= 0; d--) {
for (int i = 0; i < cnt[d]; i++) {
cout << d;
}
}
cout << endl;
return 0;
}
更简洁的写法(利用 count 函数):
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
for (char c = '9'; c >= '0'; c--) {
int t = count(s.begin(), s.end(), c);
while (t--) cout << c;
}
cout << endl;
return 0;
}
【知识点】
计数排序(桶排序) 字符串遍历与字符判断 贪心思想:大数字放高位 时间复杂度 O(n)
题二:座位(seat)
【题目描述】
CSP-J 2025 第二轮正在进行。小 R 所在的考场共有 n × m 名考生,其中所有考生的 CSP-J 2025 第一轮成绩互不相同。
所有 n × m 名考生将按照 CSP-J 2025 第一轮的成绩,由高到低蛇形分配座位,排列成 n 行 m 列。
具体地,设所有考生的成绩从高到低分别为 s₁ > s₂ > ... > s_{n×m},则:
成绩为 s₁ 的考生的座位为第 1 列第 1 行 成绩为 s₂ 的考生的座位为第 1 列第 2 行 ... 成绩为 sₙ 的考生的座位为第 1 列第 n 行 成绩为 s_{n+1} 的考生的座位为第 2 列第 n 行 ... 成绩为 s_{2n} 的考生的座位为第 2 列第 1 行 成绩为 s_{2n+1} 的考生的座位为第 3 列第 1 行 以此类推
即:第 1 列从上到下、第 2 列从下到上、第 3 列从上到下……"蛇形"排列。
给定小 R 所在的考场座位的行数 n 与列数 m,以及所有考生 CSP-J 2025 第一轮的成绩 a₁, a₂, ..., a_{n×m},其中 a₁ 为小 R 的成绩,你需要帮助小 R 求出,他的座位为第几列第几行。
【输入格式】
第一行包含两个正整数 n, m,分别表示考场座位的行数与列数。
第二行包含 n×m 个正整数 a₁, a₂, ..., a_{n×m},分别表示所有考生 CSP-J 2025 第一轮的成绩,其中 a₁ 为小 R 的成绩。
【输出格式】
输出一行两个整数,分别表示小 R 座位的列号和行号。
【样例】
样例 1 输入:
2 2
99 100 97 98
样例 1 输出:
1 2
样例 1 解释: 成绩从高到低排序:100, 99, 98, 97。
100 分:第 1 列第 1 行 99 分(小 R):第 1 列第 2 行 98 分:第 2 列第 2 行 97 分:第 2 列第 1 行
样例 2 输入:
2 2
98 99 100 97
样例 2 输出:
2 2
样例 2 解释: 成绩排序:100, 99, 98(小 R), 97。
100:第 1 列第 1 行;99:第 1 列第 2 行 98(小 R):第 2 列第 2 行;97:第 2 列第 1 行
【数据范围】
对于所有测试数据,保证:
1 ≤ n ≤ 10,1 ≤ m ≤ 10 对于所有 1 ≤ i ≤ n×m,均有 1 ≤ a_i ≤ 100 a₁, a₂, ..., a_{n×m} 互不相同
【解题思路】
这道题的核心是确定排名 → 确定位置。
第一步:计算小 R 的排名
小 R 的成绩是 a₁(第一个输入)。排名 = 1 +(分数比小 R 高的人数)。直接遍历比较即可。
第二步:根据排名计算座位
蛇形排列的规律:
每 n 个人占据一列 第 k 个人所在的列号 = ⌊(k-1)/n⌋ + 1(即第几列) 在该列中的位置(从 1 开始)= (k-1) mod n + 1
蛇形调整:
奇数列(第 1, 3, 5, ... 列):从上到下排列,行号 = 列内排名 偶数列(第 2, 4, 6, ... 列):从下到上排列,行号 = n - 列内排名 + 1
时间复杂度:O(n×m),n, m ≤ 10 完全可行。
【参考代码(C++)】
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int s; // 小 R 的成绩
cin >> s;
// 计算小 R 的排名(1-based)
int rk = 1;
for (int i = 2; i <= n * m; i++) {
int x;
cin >> x;
if (x > s) rk++; // 分数比小 R 高的,排名靠前
}
// 计算列号:每 n 人一列
int c = (rk - 1) / n + 1;
// 计算行号:考虑蛇形
int r;
if (c % 2 == 1) {
// 奇数列:从上到下
r = (rk - 1) % n + 1;
} else {
// 偶数列:��下到上
r = n - (rk - 1) % n;
}
cout << c << " " << r << endl;
return 0;
}
【知识点】
排名计算(计数比自己大的元素个数) 蛇形矩阵的位置换算 数学公式推导:rank → (col, row) 奇偶性判断
本期小结
| 题目 | 难度 | 核心算法 | 关键知识点 |
|---|---|---|---|
| 拼数 | ★☆☆ | 计数排序 | 字符串处理、贪心 |
| 座位 | ★★☆ | 数学计算 | 排名、蛇形矩阵、奇偶判断 |
下期预告:CSP-J 2025(下)— 异或和 + 多边形,敬请期待!