题解:洛谷 P14358 座位
【题目来源】
洛谷:P14358 [CSP-J 2025] 座位 / seat(民间数据) - 洛谷
【题目描述】
CSP-J 2025 第二轮正在进行。小 R 所在的考场共有 \(n \times m\) 名考生,其中所有考生的 CSP-J 2025 第一轮成绩互不相同。所有 \(n \times m\) 名考生将按照 CSP-J 2025 第一轮的成绩,由高到低蛇形分配座位,排列成 \(n\) 行 \(m\) 列。具体地,设小 R 所在的考场的所有考生的成绩从高到低分别为 \(s_1 > s_2 > \dots > s_{n \times m}\),则成绩为 \(s_1\) 的考生的座位为第 1 列第 \(1\) 行,成绩为 \(s_2\) 的考生的座位为第 \(1\) 列第 \(2\) 行,\(\dots\),成绩为 \(s_n\) 的考生的座位为第 \(1\) 列第 \(n\) 行,成绩为 \(s_{n+1}\) 的考生的座位为第 \(2\) 列第 \(n\) 行,\(\dots\),成绩为 \(s_{2n}\) 的考生的座位为第 \(2\) 列第 \(1\) 行,成绩为 \(s_{2n+1}\) 的考生的座位为第 \(3\) 列第 \(1\) 行,以此类推。
例如,若 \(n = 4, m = 5\),则所有 \(4 \times 5 = 20\) 名考生将按照 CSP-J 2025 第一轮成绩从高到低的顺序,根据下图中的箭头顺序分配座位。

给定小 R 所在的考场座位的行数 \(n\) 与列数 \(m\),以及小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩 \(a_1, a_2, \dots, a_{n \times m}\),其中 \(a_1\) 为小 R CSP-J 2025 第一轮的成绩,你需要帮助小 R 求出,他的座位为第几列第几行。
【输入】
输入的第一行包含两个正整数 \(n, m\),分别表示小 R 所在的考场座位的行数与列数。
输入的第二行包含 \(n \times m\) 个正整数 \(a_1, a_2, \dots, a_{n \times m}\),分别表示小 R 所在的考场的所有考生 CSP-J 2025 第一轮的成绩,其中 \(a_1\) 为小 R CSP-J 2025 第一轮的成绩。
【输出】
输出一行两个正整数 \(c, r\),表示小 R 的座位为第 \(c\) 列第 \(r\) 行。
【输入样例】
2 2
99 100 97 98
【输出样例】
1 2
【核心思想】
-
问题分析:给定 \(n\) 行 \(m\) 列的考场,\(n \times m\) 个互不相同的成绩按从高到低蛇形填充座位。已知小 R 的成绩 \(a_1\),求他的座位(列,行)。本质上是排序 + 蛇形矩阵定位问题:先对所有成绩降序排序,然后按蛇形规则填充矩阵,找到 \(a_1\) 对应的位置。
-
算法选择:
- 降序排序:
sort(a+1, a+1+n*m, cmp)将成绩从高到低排列 - 蛇形填充模拟:按列优先、奇数列向下、偶数列向上的规则填充矩阵
- 降序排序:
-
关键步骤:
- 读取数据:读入 \(n, m\) 和 \(n \times m\) 个成绩,记录 \(k = a[1]\)(小 R 的成绩)
- 降序排序:
sort(a+1, a+1+n*m, cmp) - 蛇形填充(\(i = 1\) 到 \(n \times m\)):
- \(b[r][c] = a[i]\)
- 若 \(a[i] = k\),输出 \((c, r)\) 并结束
- 移动规则:
- 若 \(c\) 为奇数且 \(r = n\):\(c \leftarrow c + 1\)(奇数列到底,右移)
- 若 \(c\) 为偶数且 \(r = 1\):\(c \leftarrow c + 1\)(偶数列到顶,右移)
- 若 \(c\) 为奇数:\(r \leftarrow r + 1\)(奇数列向下)
- 若 \(c\) 为偶数:\(r \leftarrow r - 1\)(偶数列向上)
-
时间/空间复杂度:
- 时间复杂度:\(O(n \cdot m \cdot \log(n \cdot m))\),排序主导
- 空间复杂度:\(O(n \cdot m)\),存储矩阵
-
蛇形矩阵的核心思想:
- 列优先的蛇形:与常见的行优先蛇形不同,本题按列填充,奇数列从上往下,偶数列从下往上
- 边界转向:每列填满后转向下一列,转向条件由当前列的奇偶性和当前行位置共同决定
- 直接模拟的简洁性:\(n, m \leq 10\)(由数组大小推断),直接模拟填充过程即可,无需数学公式推导位置
- 排序后的确定性:成绩互不相同保证排序后每个成绩的位置唯一确定
- 适用于矩阵填充、排序定位、模拟遍历类问题
【算法标签】
普及- #其他排序
【代码详解】
#include <bits/stdc++.h>
using namespace std;
// 蛇形填充规则:
// 1. 如果列数为奇数,行数为n,则列+1
// 2. 如果列数为偶数,行数为1,则列+1
// 3. 如果列数为奇数,行+1
// 4. 如果列数为偶数,行-1
int n, m; // n:行数, m:列数
int a[105]; // 存储所有输入的数字
int b[15][15]; // 蛇形填充后的矩阵
int k; // 要查找的目标数字
// 比较函数:降序排序
bool cmp(int x, int y)
{
return x > y;
}
int main()
{
// 输入行数和列数
cin >> n >> m;
// 输入所有数字
for (int i = 1; i <= n * m; i++)
{
cin >> a[i];
}
// 记录第一个数字作为目标值
k = a[1];
// 对所有数字进行降序排序
sort(a + 1, a + 1 + n * m, cmp);
// 初始化当前位置(从左上角开始)
int r = 1, c = 1; // r:行, c:列
// 蛇形填充矩阵并查找目标数字的位置
for (int i = 1; i <= n * m; i++)
{
// 将当前数字放入矩阵
b[r][c] = a[i];
// 如果找到目标数字,输出其位置(列,行)
if (a[i] == k)
{
cout << c << " " << r << endl;
return 0;
}
// 根据蛇形填充规则移动到下一个位置
// 情况1:当前列为奇数且到达最后一行,向右移动到下一列
if (c % 2 && r == n)
{
c++;
}
// 情况2:当前列为偶数且到达第一行,向右移动到下一列
else if (c % 2 == 0 && r == 1)
{
c++;
}
// 情况3:当前列为奇数,向下移动一行
else if (c % 2)
{
r++;
}
// 情况4:当前列为偶数,向上移动一行
else
{
r--;
}
}
return 0;
}
【运行结果】
2 2
99 100 97 98
【算法真传】
浙公网安备 33010602011771号