原题链接:小白月赛106-B
题目描述
明白 你那份跳动的爱
别再 装作着无所谓的姿态
现在 就跟着节奏摇摆
将所有的伪装抛开
——阿良良木健《末日DISCO》
给定一个正整数 n,你需要构造 n 个集合 S₁, S₂, …, Sₙ,每个集合均含有 n 个元素,且满足:
-
在每个集合中,每个数最多出现 1 次。
-
任意两个集合 Sᵢ, Sⱼ 满足 i ≠ j,都有 |Sᵢ ∩ Sⱼ| = 1,即 Sᵢ 和 Sⱼ 的交集的大小均为 1。
-
对于所有在 S₁, S₂, …, Sₙ 中出现过的元素 x,x 在所有集合的出现次数之和必须小于等于 2。
-
集合中的元素 x 必须满足 1 ≤ x ≤ 10⁶。
输入描述
一行一个正整数 n (1 ≤ n ≤ 500)。
示例
输入
// 3输出
// 1 2 3// 3 4 5// 1 5 6接下来是题解。我们首先看示例,示例这里的正确输出其实不唯一,如下面这种矩阵
// 1 2 3// 2 4 5// 3 5 6本人认为这种矩阵比示例的矩阵更有规律。n × n 的矩阵,对于每一行,从第 i 行的 i − 1 索引到该行的 n − 1 索引上的整数是连续的。对于每一列,从第 j 列的 j − 1 索引到该列的 n − 1 索引上的整数是连续的。行与列的规则相似,并且对于每一行/列,又有第 i 行/列 n−1 索引上的数(末尾上的数),与第 i + 1 行/列 j 索引上的数连续。
注:i 或者 j 都满足 1 ≤ i, j ≤ n (该不会真的有人用第 0 行这种说法吧),每行/列的索引是从 0 开始到 n − 1
题解代码-C语言版本
#define _CRT_SECURE_NO_WARNINGS //没错,我用的是VS2022#include <stdio.h>
int main(){int n = 0;int num = 1;long arr[502][502] = { 0 };
scanf("%d", &n);
for (int i = 0, z = 0; i <= n - 1; i++, z++){for (int j = z; j <= n - 1; j++){arr[i][j] = num;arr[j][i] = num++;}}
for (int i = 0; i <= n - 1; i++){for (int j = 0; j <= n - 1; j++){printf("%ld ", arr[i][j]);}printf("\n");}
return 0;}核心代码
int num = 1;...for (int i = 0, z = 0; i <= n - 1; i++, z++){for (int j = z; j <= n - 1; j++){arr[i][j] = num;arr[j][i] = num++;}}这里使用行优先的双层 for 循环,i 是行对应索引,这里用一个变量 z 记录每一行递增序列的开始索引。这里看内层的循环,j 会初始化为 z 记录的值,也就是说我们仅从每一行递增序列的开始索引开始构造矩阵。因为这种矩阵的 (i, j) 位置上与 (j, i) 位置上的数是相同的,我们在对 (i, j) 位置上的元素赋值时同时对 (j, i) 位置赋值就行
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时