文章目录
T1. 拼数
小 R 正在学习字符串处理。小 X 给了小 R 一个字符串 s s s,其中 s s s 仅包含小写英文字母及数字,且包含至少一个 1 ∼ 9 1 \sim 9 1∼9 中的数字 。小 X 希望小 R 使用 s s s 中的任意多个数字,按任意顺序拼成一个正整数。注意:小 R 可以选择 s s s 中相同的数字,但每个数字只能使用一次 。例如,若 s s s 为 1 a 01 b \tt 1a01b 1a01b,则小 R 可以同时选择第 1 , 3 , 4 1,3,4 1,3,4 个字符,分别为 1 , 0 , 1 1,0,1 1,0,1,拼成正整数 101 101 101 或 110 110 110;但小 R 不能拼成正整数 111 111 111,因为 s s s 仅包含两个数字 1 1 1。小 R 想知道,在他所有能拼成的正整数中,最大的是多少。你需要帮助小 R 求出他能拼成的正整数的最大值。
时间限制:1 s
内存限制:512 MB
-
输入
输入的第一行包含一个字符串 s s s,表示小 X 给小 R 的字符串。
-
输出
输出一行一个正整数,表示小 R 能拼成的正整数的最大值。
-
样例输入 1
a5 -
样例输出 1
a5 -
样例输入 2
a290es1q0 -
样例输出 2
a92100 -
数据规模与约定
设 ∣ s ∣ |s| ∣s∣ 为字符串 s s s 的长度。对于所有测试数据,保证:
- 1 ≤ ∣ s ∣ ≤ 10 6 1 \leq |s| \leq 10^6 1≤∣s∣≤106;
- s s s 仅包含小写英文字母及数字,且包含至少一个 1 ∼ 9 1 \sim 9 1∼9 中的数字。
思路分析
此题考查字符处理与贪心排序/桶计数,属于入门签到题。
要使组成的整数最大,核心策略是高位数值越大越好。
- 遍历输入的字符串,提取出所有的数字字符;
- 使用桶计数统计
0到9每个数字出现的次数; - 从数字
9到0依次输出对应的数量,即可得到最大的重组整数。
算法时间复杂度为 O ( ∣ S ∣ ) O(\vert{}S\vert{}) O(∣S∣),空间复杂度为 O ( 1 ) O(1) O(1)。
cpp
/*
* Name: T1.cpp
* Problem: 拼数
* Author: Teacher Gao.
* Date&Time: 2026/09/29 20:46
*/
#include <bits/stdc++.h>
using namespace std;
int cnt[10];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
string s;
cin >> s;
for (char ch : s) {
if (isdigit(ch)) {
cnt[ch - '0']++;
}
}
for (int i = 9; i >= 0; i--) {
while (cnt[i]--) {
cout << i;
}
}
return 0;
}
T2. 座位
CSP-J 2025 第二轮正在进行。小 R 所在的考场共有 n × m n \times m n×m 名考生,其中所有考生的 CSP-J 2025 第一轮成绩互不相同 。所有 n × m n \times m n×m 名考生将按照 CSP-J 2025 第一轮的成绩,由高到低蛇形分配座位 ,排列成 n n n 行 m m m 列 。具体地,设小 R 所在的考场的所有考生的成绩从高到低 分别为 s 1 > s 2 > ⋯ > s n × m s_1 > s_2 > \dots > s_{n \times m} s1>s2>⋯>sn×m,则成绩为 s 1 s_1 s1 的考生的座位为第 1 列 第 1 1 1 行 ,成绩为 s 2 s_2 s2 的考生的座位为第 1 1 1 列 第 2 2 2 行 , ... \dots ...,成绩为 s n s_n sn 的考生的座位为第 1 1 1 列 第 n n n 行 ,成绩为 s n + 1 s_{n+1} sn+1 的考生的座位为第 2 2 2 列 第 n n n 行 , ... \dots ...,成绩为 s 2 n s_{2n} s2n 的考生的座位为第 2 2 2 列 第 1 1 1 行 ,成绩为 s 2 n + 1 s_{2n+1} s2n+1 的考生的座位为第 3 3 3 列 第 1 1 1 行,以此类推。
例如,若 n = 4 , m = 5 n = 4, m = 5 n=4,m=5,则所有 4 × 5 = 20 4 \times 5 = 20 4×5=20 名考生将按照 CSP-J 2025 第一轮成绩从高到低的顺序,根据下图中的箭头顺序分配座位。

给定小 R 所在的考场座位的行数 n n n 与列数 m m m,以及小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩 a 1 , a 2 , ... , a n × m a_1, a_2, \dots, a_{n \times m} a1,a2,...,an×m,其中 a 1 a_1 a1 为小 R CSP-J 2025 第一轮的成绩,你需要帮助小 R 求出,他的座位为第几列 第几行。
时间限制:1 s
内存限制:512 MB
-
输入
输入的第一行包含两个正整数 n , m n, m n,m,分别表示小 R 所在的考场座位的行数 与列数 。
输入的第二行包含 n × m n \times m n×m 个正整数 a 1 , a 2 , ... , a n × m a_1, a_2, \dots, a_{n \times m} a1,a2,...,an×m,分别表示小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩,其中 a 1 a_1 a1 为小 R CSP-J 2025 第一轮的成绩。
-
输出
输出一行两个正整数 c , r c, r c,r,表示小 R 的座位为第 c c c 列 第 r r r 行。
-
样例输入 1
a2 2 99 100 97 98 -
样例输出 1
a1 2 -
样例输入 2
a2 2 98 99 100 97 -
样例输出 2
a2 2 -
样例输入 3
a3 3 94 95 96 97 98 99 100 93 92 -
样例输出 3
a3 1 -
数据规模与约定
对于所有测试数据,保证:
- 1 ≤ n ≤ 10 1 \leq n \leq 10 1≤n≤10, 1 ≤ m ≤ 10 1 \leq m \leq 10 1≤m≤10;
- 对于所有 1 ≤ i ≤ n × m 1 \leq i \leq n \times m 1≤i≤n×m,均有 1 ≤ a i ≤ 100 1 \leq a_i \leq 100 1≤ai≤100,且 a 1 , a 2 , ... , a n × m a_1, a_2, \dots, a_{n \times m} a1,a2,...,an×m 互不相同。
思路分析
此题考查数学坐标推导与蛇形走位,属于基础模拟题。
在保证所有人成绩互不相同的情况下,目标学生的排名 k = ( 成绩高于该学生的人数 ) + 1 k = (\text{成绩高于该学生的人数}) + 1 k=(成绩高于该学生的人数)+1。可以通过遍历一次成绩序列直接统计得出。
蛇形坐标换算:
- 列号 c c c :每列安排 n n n 个座位,故列号为 c = ⌊ ( k − 1 ) / n ⌋ + 1 c = \lfloor (k - 1) / n \rfloor + 1 c=⌊(k−1)/n⌋+1。
- 行号 r r r :在第 c c c 列中的相对偏移量为 i d x = ( k − 1 ) m o d n idx = (k - 1) \bmod n idx=(k−1)modn。
- 若 c c c 为奇数 (从上到下):行号 r = i d x + 1 r = idx + 1 r=idx+1;
- 若 c c c 为偶数 (从下到上):行号 r = n − i d x r = n - idx r=n−idx。
算法时间复杂度为 O ( n × m ) O(n \times m) O(n×m),空间复杂度为 O ( n × m ) O(n \times m) O(n×m)。
cpp
/*
* Name: T2.cpp
* Problem: 座位
* Author: Teacher Gao.
* Date&Time: 2026/09/29 20:55
*/
#include <bits/stdc++.h>
using namespace std;
int a[105];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int n, m;
cin >> n >> m;
int total = n * m, cnt = 0;
for (int i = 1; i <= total; i++) {
cin >> a[i];
cnt += a[i] > a[1];
}
int k = cnt + 1;
int c = (k - 1) / n + 1, idx = (k - 1) % n, r;
if (c % 2 != 0) r = idx + 1;
else r = n - idx;
cout << c << " " << r << "\n";
return 0;
}
T3. 异或和
小 R 有一个长度为 n n n 的非负整数序列 a 1 , a 2 , ... , a n a_1, a_2, \dots, a_n a1,a2,...,an。定义一个区间 l , r l, r l,r ( 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1≤l≤r≤n) 的权值为 a l , a l + 1 , ... , a r a_l, a_{l+1}, \dots, a_r al,al+1,...,ar 的二进制按位异或和,即 a l ⊕ a l + 1 ⊕ ⋯ ⊕ a r a_l \oplus a_{l+1} \oplus \dots \oplus a_r al⊕al+1⊕⋯⊕ar,其中 ⊕ \oplus ⊕ 表示二进制按位异或。
小 X 给了小 R 一个非负整数 k k k。小 X 希望小 R 选择序列中尽可能多的不相交 的区间,使得每个区间的权值均为 k k k。两个区间 l 1 , r 1 , l 2 , r 2 l_1, r_1, l_2, r_2 l1,r1,l2,r2 相交当且仅当两个区间同时包含至少一个相同的下标,即存在 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n 使得 l 1 ≤ i ≤ r 1 l_1 \leq i \leq r_1 l1≤i≤r1 且 l 2 ≤ i ≤ r 2 l_2 \leq i \leq r_2 l2≤i≤r2。
例如,对于序列 2 , 1 , 0 , 3 2, 1, 0, 3 2,1,0,3,若 k = 2 k = 2 k=2,则小 R 可以选择区间 1 , 1 1, 1 1,1 和区间 2 , 4 2, 4 2,4,权值分别为 2 2 2 和 1 ⊕ 0 ⊕ 3 = 2 1 \oplus 0 \oplus 3 = 2 1⊕0⊕3=2;若 k = 3 k = 3 k=3,则小 R 可以选择区间 1 , 2 1, 2 1,2 和区间 4 , 4 4, 4 4,4,权值分别为 1 ⊕ 2 = 3 1 \oplus 2 = 3 1⊕2=3 和 3 3 3。
你需要帮助小 R 求出他能选出的区间数量的最大值。
时间限制:1 s
内存限制:512 MB
- 输入
输入的第一行包含两个非负整数 n , k n, k n,k,分别表示小 R 的序列长度和小 X 给小 R 的非负整数。
输入的第二行包含 n n n 个非负整数 a 1 , a 2 , ... , a n a_1, a_2, \dots, a_n a1,a2,...,an,表示小 R 的序列。 - 输出
输出一行一个非负整数,表示小 R 能选出的区间数量的最大值。 - 样例输入 1
a
4 2
2 1 0 3
- 样例输出 1
a
2
- 样例输入 2
a
4 3
2 1 0 3
- 样例输出 2
a
2
- 样例输入 3
a
4 0
2 1 0 3
- 样例输出 3
a
1
- 数据规模与约定
对于所有测试数据,保证:- 1 ≤ n ≤ 5 × 10 5 1 \leq n \leq 5 \times 10^5 1≤n≤5×105, 0 ≤ k < 2 20 0 \leq k < 2^{20} 0≤k<220;
- 对于所有 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,均有 0 ≤ a i < 2 20 0 \leq a_i < 2^{20} 0≤ai<220。
思路分析
此题考查前缀异或和 + 贪心区间划分,属于中等偏易题目。
维护当前位置的前缀异或和 S i = a 1 ⊕ a 2 ⊕ ⋯ ⊕ a i S_i = a_1 \oplus a_2 \oplus \dots \oplus a_i Si=a1⊕a2⊕⋯⊕ai(约定 S 0 = 0 S_0 = 0 S0=0)。区间 l , r l, r l,r 的异或和恰好等于 k k k,等价于 S r ⊕ S l − 1 = k ⟺ S l − 1 = S r ⊕ k S_r \oplus S_{l-1} = k \iff S_{l-1} = S_r \oplus k Sr⊕Sl−1=k⟺Sl−1=Sr⊕k。
要使选出的不相交区间数量尽可能多,每当发现一个合法的区间 l , r l, r l,r 时,我们应当优先选择右端点 r r r 尽可能靠左的区间(即越早结束越好),这样可以给后续区间留出最多的选择空间。
遍历数组的过程中边读入边维护当前异或和 s,用 p 记录上一次选定的合法区间的右端点 (初始 p = 0),用哈希表 mp[val] 记录前缀异或值 val 最近一次出现的下标。若 mp.find(s ^ k) 存在且其出现的下标满足 mp[s ^ k] >= p,说明找到了一组不与前面重叠的合法区间,此时答案计数 tot++,并将区间右端点更新为当前下标 p = i。最后更新 mp[s] = i。
算法时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)。
cpp
/*
* Name: T3.cpp
* Problem: 异或和
* Author: Teacher Gao.
* Date&Time: 2026/09/29 21:09
*/
#include <bits/stdc++.h>
using namespace std;
int n, k, x, s, tot, p = 0;
unordered_map<int, int> mp;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> k;
mp[0] = 0;
for (int i = 1; i <= n; i++) {
cin >> x;
s ^= x;
// 检查是否存在合法的左端点,且该左端点不早于上个选定区间的右端点 p
if (mp.find(s ^ k) != mp.end() && mp[s ^ k] >= p) {
tot++;
p = i; // 贪心选择当前下标 i 作为新区间的右端点
}
// 更新当前前缀异或和 s 最新出现的位置
mp[s] = i;
}
cout << tot;
return 0;
}
T4. 多边形
小 R 喜欢玩小木棍。小 R 有 n n n 根小木棍,第 i i i( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n)根小木棍的长度为 a i a_i ai。
小 X 希望小 R 从这 n n n 根小木棍中选出若干根小木棍,将它们按任意顺序首尾相连拼成一个多边形。小 R 并不知道小木棍能拼成多边形的条件,于是小 X 直接将条件告诉了他:对于长度分别为 l 1 , l 2 , ... , l m l_1, l_2, \dots, l_m l1,l2,...,lm 的 m m m 根小木棍,这 m m m 根小木棍能拼成一个多边形当且仅当 m ≥ 3 m \geq 3 m≥3 且所有小木棍的长度之和大于 所有小木棍的长度最大值的两倍,即 ∑ i = 1 m l i > 2 × max i = 1 m l i \sum_{i=1}^{m} l_i > 2 \times \max_{i=1}^{m} l_i ∑i=1mli>2×maxi=1mli。
由于小 R 知道了小木棍能拼成多边形的条件,小 X 提出了一个更难的问题:有多少种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形?你需要帮助小 R 求出选出的小木棍能够拼成一个多边形的方案数。两种方案不同当且仅当选择的小木棍的下标集合不同 ,即存在 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,使得其中一种方案选择了第 i i i 根小木棍,但另一种方案未选择。由于答案可能较大,你只需要求出答案对 998 , 244 , 353 998,244,353 998,244,353 取模后的结果。
时间限制:1.5 s
内存限制:512 MB
-
输入
输入的第一行包含一个正整数 n n n,表示小 R 的小木棍的数量。
输入的第二行包含 n n n 个正整数 a 1 , a 2 , ... , a n a_1, a_2, \dots, a_n a1,a2,...,an,表示小 R 的小木棍的长度。
-
输出
输出一行一个非负整数,表示小 R 选出的小木棍能够拼成一个多边形的方案数对 998 , 244 , 353 998,244,353 998,244,353 取模后的结果。
-
样例输入 1
a5 1 2 3 4 5 -
样例输出 1
a9 -
样例输入 2
a5 2 2 3 8 10 -
样例输出 2
a6 -
数据规模与约定
对于所有测试数据,保证:
- 3 ≤ n ≤ 5 , 000 3 \leq n \leq 5,000 3≤n≤5,000;
- 对于所有 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,均有 1 ≤ a i ≤ 5 000 1 \leq a_i \leq 5\,000 1≤ai≤5000。
思路分析
此题考查排序 + 容斥原理(正难则反) + 0/1 背包 DP,属于综合提高题。
如果直接求解合法组合,不仅需要维护复杂的集合大小,还会导致背包状态上界膨胀到 ∑ a i ≈ 2.5 × 10 7 \sum a_i \approx 2.5 \times 10^7 ∑ai≈2.5×107 而超时。我们可以运用容斥思想(正难则反) :
合法多边形方案数 = 所有非空子集总数 ( 2 n − 1 ) − 所有不能构成多边形的非空子集数 \text{合法多边形方案数} = \text{所有非空子集总数 } (2^n - 1) - \text{所有不能构成多边形的非空子集数} 合法多边形方案数=所有非空子集总数 (2n−1)−所有不能构成多边形的非空子集数
将所有木棍升序排序 a 1 ≤ a 2 ≤ ⋯ ≤ a n a_1 \le a_2 \le \dots \le a_n a1≤a2≤⋯≤an。维护 DP 数组 f[j],表示在前 i i i 个木棍中,选出木棍总长度为 j j j 的子集方案数。设 C = max ( a i ) = a n ≤ 5000 C = \max(a_i) = a_n \le 5000 C=max(ai)=an≤5000,我们只需维护容量上界为 C C C 的背包 :
f j = ( f j + f j − a i ) m o d M O D ( j = C 降序到 a i ) \text{f}j = (\text{f}j + \text{f}j - a_i) \bmod MOD \quad (j = C \text{ 降序到 } a_i) fj=(fj+fj−ai)modMOD(j=C 降序到 ai)
在更新之前先把以 a i a_i ai 为最大值的子集不合法情况累计到 tot 中,以 a i a_i ai 为最大值的子集不合法的条件是其余边的总长度 j ≤ a i j \le a_i j≤ai 。所以,直接累加 ∑ j = 0 a i f j \sum_{j=0}^{a_i} \text{f}j ∑j=0aifj,即可准确将所有 "以 a i a_i ai 为最大边且不能拼成多边形" 的非空子集计入不合法总数 tot 中。
时间复杂度为 O ( n × max a i ) O(n \times \max a_i) O(n×maxai),在 n ≤ 5000 , a i ≤ 5000 n \le 5000, a_i \le 5000 n≤5000,ai≤5000 下,计算量约为 5000 × 5000 = 2.5 × 10 7 5000 \times 5000 = 2.5 \times 10^7 5000×5000=2.5×107 次。空间复杂度为 O ( max a i ) O(\max a_i) O(maxai)。
cpp
/*
* Name: T4.cpp
* Problem: 多边形
* Author: Teacher Gao.
* Date&Time: 2026/09/29 21:26
*/
#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
long long quick_power(long long x, int y) {
long long ret = 1;
while (y) {
if (y & 1) ret = (ret * x) % MOD;
x = (x * x) % MOD;
y >>= 1;
}
return ret;
}
int n;
int a[5005];
long long f[5005] = {1}, tot;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1);
int C = a[n];
for (int i = 1; i <= n; i++) {
// 以 a[i] 为最长边的不合法情况:其余边总长 ≤ a[i]
for (int j = 0; j <= a[i]; j++) {
tot = (tot + f[j]) % MOD;
}
for (int j = C; j >= a[i]; j--) {
f[j] = (f[j] + f[j - a[i]]) % MOD;
}
}
// 子集总数 - 空集数 - 不能构成多边形的子集数
cout << (quick_power(2, n) - 1 - tot + MOD) % MOD;
return 0;
}