NOIP 提高组初赛 · NOIP 2008 提高组初赛试题 第 28 题

阅读程序 · 答案 j++;j+=1;j=j+1;a[i][j] > ka[i][j] < kanswerx = i;answery = j; · 考点:二维数组与多维数组、双指针、循环结构、基础算法

← 整套速查表 NOIP 提高组初赛 全部真题

题目

(矩阵中的数字)有一个 $n\times n(1\leq n\leq 5000)$ 的矩阵 $a$,对于 $1\leq i<n, 1\leq j\leq n$,$a_{i,j} < a_{i + 1,j},a_{j,i} < a_{j,i+1}$。即矩阵中左右相邻的两个元素,右边的元素一定比左边的大。上下相邻的两个元素,下面的元素一定比上面的大。给定矩阵 $a$ 中的一个数字 $k$,找出 $k$ 所在的行列(注意:输入数据保证矩阵中的数各不相同)。

#include <iostream>
using namespace std;
int n,k,answerx,answery;
int a[5001][5001];
void FindKPosition()
{
	int i = n,j = n;
	while (j > 0)
	{
		if (a[n][j] < k) break;               
		j --;
	}
        ①        
	while (a[i][j] != k)
	{
		while (              ②              && i > 1) i --;
		while (              ③              && j <= n) j ++;
	}
	              ④             
	              ⑤             
}

int main()
{
	int i,j;
	cin >> n;
	for (i = 1;i <= n;i ++)
		for (j = 1;j <= n;j ++)
			cin >> a[i][j];
	cin >> k;
	FindKPosition();
	cout << answerx << " " << answery << endl;
     return 0;
}
答案:j++;j+=1;j=j+1;a[i][j] > ka[i][j] < kanswerx = i;answery = j;

考点

二维数组与多维数组双指针循环结构基础算法

解题思维

这道题考的是有序矩阵查找,核心是双指针:从右下角出发,当前值太大就往上,太小就往右,直到找到目标。

常见错误

最容易掉进的坑是第一步的补偿逻辑。很多学生看到 while 循环里 j 在递减,就以为直接接着用,忘了循环结束时 j 已经比目标列少了一,必须加回 1 才能正确定位。另外,在判断移动方向时,容易把大于号小于号写反,或者忘记边界条件 i>1 和 j<=n,导致数组越界或死循环。还有,最后输出行列时,题目要求先输出行再输出列,顺序搞反也是高频错误。

详细解析(节选)

题目考查核心:在一个行和列都严格递增的矩阵中,给定一个数 k,找出它所在的行和列。这属于典型的有序矩阵查找问题,也是信息学竞赛中常考的双指针技巧应用场景。

概念与性质:题目给出的条件非常关键——矩阵中左右相邻的元素,右边的大于左边;上下相邻的元素,下边的大于上边。这意味着矩阵的每一行是递增的,每一列也是递增的。同时,题目保证矩阵中的数各不相同,这简化了逻辑,不需要处理重复值的情况。

命题人视角:命题人喜欢在这种看似简单的矩阵中挖坑。第一,他们会在起始位置的确定上设障,比如让你先往左找,但循环结束后位置不对,考验你是否细心。第二,移动方向的判断条件容易写反,或者漏掉边界检查(比如 i 不能小于 1,j 不能大于 n)。第三,输出顺序容易搞混,行和列的先后顺序必须严格对应题目要求。

思考心法:拿到这道题,首先要明确搜索策略。既然矩阵有序,我们不需要暴力遍历所有元素,那样时间复杂度是 O(n²),对于 n=5000 显然会超时。我们需要一种能利用有序性的方法,把复杂度降到 O(n)。经典的思路是从右下角开始。为什么选右下角?因为从这里出发,无论往左走还是往上走,都能缩小搜索范围。如果当前元素比 k 大,说明 k 不可能在当前列的下方(因为下方更大),只能往上找;如果当前元素比 k 小,说明 k 不可能在当前行的左方(因为左方更小),只能往右找。这样每一步都能排除掉一行或一列,最多走 n 步就能找到。

算法推演与填空: 1. 第一阶段:确定起始列。代码从 i=n, j=n 开始,也就是右下角。然后进入一个 while 循环,条件是 j>0,循环体内判断 a[n][j] < k。如果最后一行的元素小于 k,说明 k 一定在这一列的下方或者更右边的列中,所以循环终止,j 停在第一个小于 k 的位置。但注意,循环结束后 j 已经比目标列少了一(因为循环是 j-- 直到条件满足),所以必须执行 ① j++ 来补偿,回到正确的那个列。这是第一个坑,很多同学会漏掉这一步,导致后续搜索从错误的位置开始。 2. 第二阶段:双指针搜索。现在 j 已经确定,i 还是 n。进入外层 while 循环,条件是 a[i][j] != k。只要没找到 k,就不断调整 i 和 j。调整逻辑是:如果当前元素太大(a[i][j] > k),说明 k 在上方,所以 i--;如果当前元素太小(a[i][j] < k),说明 k 在右方,所以 j++。这里要注意两个内层 while 循环的条件:往上走必须保证 i>1,往右走必须保证 j<=n,否则数组越界。所以 ② 填 a[i][j] > k,③ 填 a[i][j] < k。 3. 结束与输出。当外层循环退出时,说明 a[i][j] == k,找到了目标。此时需要把 i 和 j 分别赋给答案变量。题目要求输出行和列,所以先输出行,再输出列。因此 ④ 填 answerx = i,⑤ 填 answery = j。

避坑指南:

考频与趋势:

预测:基于上述数据,循环结构在未来几年仍将是绝对的高频考点,尤其是 2026 年预测有 161 题,这可能与 CSP-J/S 或 GESP 级别的考试改革有关。二维数组的考频也在逐年上升,2026 年预测有 9 题,说明对多维数组的考察会越来越细致。双指针虽然考得少,但作为解决有序矩阵查找等问题的利器,未来可能会在更复杂的场景中出现,比如带权重的矩阵搜索或动态规划中的指针优化。暂无足够依据预测双指针在未来会有爆发式增长,但保持对这类技巧的敏感度是必要的。

同考点真题

在 OI伴学 里做这道题
登录后可计时作答、查看完整六段式解析,并按你的错题自动生成同类练习。
去刷题先做一次 AI 学情诊断