P9837 汪了个汪
和 Jryno1 赛时独立想到了同一个做法,感觉比现在两篇官方题解都更可能被想到一些。
所有行列的编号取 0-index,列从左往右,行从上到下。
观察样例。

仔细看那个 2211,$2$ 的两侧有 $3,4,5$,$1$ 左右侧有 $2,3,4,5$。再看左下角那个 34,$4$ 的左右有 $3$ 和 $5$,$3$ 的左右有 $5$。
为了与后面的说明相符合,把它写成
1
3 2
5 2 4
4 1 5 3
2 1 3 4 5
的样子。
我们尝试逐列扩展,每次扩展两列。具体说,我们在第 $2i+1$ 列(列取 0-index)放 $2i+1$ 和 $2i+2$,使得加上之前放下的数字,所有包含 $2i+1$ 和 $2i+2$ 的数对都出现。
注意到对于 $x < 2i+1$,$(x, 2i+1)$ 已经出现。因此,实际上需要新出现 $2n-4i-3$ 个数对。
第 $x$ 列有 $n-x$ 个数字,左右两列加起来有 $2n-4i-2$ 个数对,注意到左边那一行最上面那一个数字不能与这一行形成数对,因此,这三列能组成所有我们需要的数对。
考虑构造。
经过大量手玩(赛时将近 2h,写搜索可能会快一些),我们构造出了一个 $n=7$ 的情况。
1
3 2
5 1 4
7 2 6 3
6 1 7 4 5
4 2 5 3 7 6
2 1 3 4 6 5 7
仔细观察它,偶数列是一段奇数拼一段偶数,奇数列是 $i$ 与 $i+1$ 交替。
对于偶数列,大的数字在中间,奇数在上的情况和偶数在上的情况交替。
对于奇数列,奇偶数交替,哪种数字在前也交替。
如果听不懂文字描述可以看一看 $n=9$,务必分奇偶列去看。
1
3 2
5 1 4
7 2 6 3
9 1 8 4 5
8 2 9 3 7 6
6 1 7 4 9 5 8
4 2 5 3 8 6 9 7
2 1 3 4 6 5 7 8 9
我都快忘了自己怎么想到的了,反正玩了很久后终于找到了那组解。
这是 $n$ 为奇数,那偶数怎么办呢?
你发现斜线是一个排列,因此在每一行最后加一个 $n$ 就行了。(谢谢 @Register_int)
代码
#include <bits/stdc++.h>
int main() {
int n; scanf("%d", &n);
std::vector<std::vector<int>> f(n, std::vector<int> (n));
bool q = 0;
if (n % 2 == 0) q = 1, --n;
for (int i = 0; i < n; i += 2) {
if (i % 4 == 0) {
int p = i;
for (int j = i + 1; j <= n; j += 2)
f[p++][i] = j;
p = n - 1;
for (int j = i + 2; j <= n; j += 2)
f[p--][i] = j;
} else {
int p = n - 1;
for (int j = i + 1; j <= n; j += 2)
f[p--][i] = j;
p = i;
for (int j = i + 2; j <= n; j += 2)
f[p++][i] = j;
}
}
for (int i = 1; i < n; i += 2) {
if (i % 4 == 1) {
std::vector<int> val(2);
val[0] = i, val[1] = i + 1;
for (int j = n - 1; j >= i; j--)
f[j][i] = val[(n - 1 - j) & 1];
} else {
std::vector<int> val(2);
val[0] = i + 1, val[1] = i;
for (int j = n - 1; j >= i; j--)
f[j][i] = val[(n - 1 - j) & 1];
}
}
if (q) printf("%d\n", n + 1);
for (int i = 0; i < n; i++) {
for (int j = 0; j <= i; j++) printf("%d ", f[i][j]);
if (q) printf("%d ", n + 1);
printf("\n");
}
}
本文来自博客园,作者:purplevine,转载请注明原文链接:https://www.cnblogs.com/purplevine/p/17914823.html

浙公网安备 33010602011771号