✅
Chorus ☁️
上一题链接: C/C++百题打卡[5/100]——合唱队形⭐️⭐️ 考查数组.
百题打卡总目录: 🚧 🚧 …
一、题目总述
● 给定正整数 n n n、 m m m、 k k k 能否将一个 n × m n\times m n×m 的表格染色,使得每一个颜色形成恰好一个连通块,并且每一个连通块的 “面积” 为 k k k?如果存在,请构造一个合法方案。
● 输入描述:
共二行。
第一行是一个整数 T T T,表示测试数据的次数。
接下来 T T T 行,每行三个正整数 n n n、 m m m、 k k k。
● 输出描述:
输出 T T T 行。
如果存在,第一行先输出YES
,否则,输出NO
。
如果存在,接下来输出 n n n 行,其中每行 m m m 个正整数,其中每一堆 “正整数群” 正好形成一个 “面积大小” 恰好为 k k k 的连通块。
● 注意:
①运行限制——>最大运行时间: 2 s 2s 2s,最大运行内存: 512 M 512M 512M; ②对于 100 100% 100 的数据,保证有 1 ≤ n , m , k , T , n × m ≤ 1 0 6 1\le n,m,k,T,n \times m\le10^{6} 1≤n,m,k,T,n×m≤106
● 挑战成功率: 8.64 % 8.64\% 8.64%【很多人评论此题难度不应该是入门,我也觉得,起码是中等难度】
● 输入样例:
3
3 3 3
3 3 33
6 6 4
● 输出样例:
YES
1 1 2
1 2 2
3 3 3
NO
YES
1 1 2 2 3 3
1 2 2 4 4 3
1 5 5 4 6 3
5 5 7 4 6 6
8 7 7 7 9 6
8 8 8 9 9 9
● 样例解释:对于样例一的 “3 3 3” 的一种合法输出示意图如下:
二、思考空白区
● 题目难度:⭐️⭐️⭐️
● 建议思考时间:⌛️ ⌛️ ⌛️
三、题目解析
● 这是一道考查数组
的题。主要是别想复杂了,我一开始就想复杂了,做了很久,虽然最后没有通过 “常规方法” 做了出来,但花费了一个小时的时间。而如果想通了的话,只需要10
分钟就能做出来。
● 首先,根据基本的数学知识可知,若 n × m ÷ k n \times m÷k n×m÷k 有余数的话,那就说明,无论如何涂色, n × m n\times m n×m 的表格都不能被以 k k k 为面积大小的连通块涂满。
● 其次,当我们的判断结果为 “YES” 后,我们考虑如何打印这个 n × m n \times m n×m 的矩阵呢?
● 关键就是这里,只要我们抓住题目中的一个关键字 —— 它只要求 “面积大小相同” 的连通块,而没要求连通块的形状都相同(当时我就这么做了…)。所以,我们只要用 “蛇形” 涂色即可,示意图如下:
● 算法设计:
[1]
设计 输入模块
[2]
设计 蛇形矩阵模块
[3]
设计 输出模块
第[1]步:输入模块
#include <stdio.h>
int main()
{
/* 输入模块 */
int T, n, m, k;
cin >> T;
while (T > 0)
{
T--;
...
scanf("%d%d%d", &n, &m, &k);
if (n * m % k != 0)
{
printf("NO\n");
}
else
{
printf("YES\n");
/* 蛇形矩阵模块 */
...
/* 输出模块 */
...
}
}
}
return 0;
}
第[2]步:蛇形矩阵模块
● 设计思路:
① 先初始化一个计数器tim = 0
,每涂一次就tim++
,当涂了 “k” 个方块时,就进行重新赋值为1
。
② 同时初始化一个涂色数字cnt = 1
(也就是我们要打印的数字),只有当涂了 “k” 个方块后,执行一次cnt++
。
③ 我们需要将涂色的数字先存储起来(存在a[]
中),然后在处理完每一行时,再在最后输出a[]
。因为当我们要打印那种 “向右回转再朝左的那种蛇形” 时,我们还并不知道那个 “蛇形” 之前涂色数字(如上图所示的黑色箭头)。
④ 所以,我们考虑用一个标志flag
来表示,这个 “蛇形”,是向 →,还是向 ←。
#include <stdio.h>
int a[1000010];
int main()
{
/* 输入模块 */
int T, n, m, k;
cin >> T;
while (T > 0)
{
T--;
/* 每一轮都要初始化 */
int cnt = 1;
int tim = 0;
int flag = 1;
/****************/
scanf("%d%d%d", &n, &m, &k);
if (n * m % k != 0)
{
printf("NO\n");
}
else
{
printf("YES\n");
/*********** 蛇形矩阵模块 **********/
for (int i = 1; i <= n; i++)
{
if (flag == 1) // 顺向蛇形处理
{
for (int j = 1; j <= m; j++)
{
tim++;
if (tim > k)
{
cnt++;
tim = 1;
}
a[j] = cnt; // 存储 “涂色数字”
}
flag = -flag; // 输完了这一行时, 蛇形准备转向
}
else
{
for (int j = m; j >= 1; j--) // 逆向蛇形处理
{
tim++;
if (tim > k)
{
cnt++;
tim = 1;
}
a[j] = cnt;
}
flag = -flag; // 输完了这一行时, 蛇形准备转向
}
/**************************/
/* 输出模块 */
...
}
}
}
return 0;
}
第[3]步:输出模块
● 这个相对简单点,把a[]
依次输出即可。注意的是,按题目要求,数组的空间需比
1
0
6
10^6
106 大。
/* 输出模块 */
for (int j = 1; j <= m; j++)
printf("%d ", a[j]);
printf("\n");
四、做题小结与反思
● 这道题的确,我感觉,做题做多了,一看到就知道用 “蛇形矩阵”。但做得少就可能会耗很多时间。
● 我简单谈谈我之前用的第一种方法(不是蛇形矩阵):
① 判断 “YES” 和 “NO” 的机制是一样的。
② 然后找出
k
k
k 的所有配对的 “质因数对
a
i
×
b
i
a_i\times b_i
ai×bi”。
③ 然后把这一系列的 “质因数对” 作为除数,被除数是
n
n
n 和
m
m
m。找到能除得尽的 “质因数对
a
k
×
b
k
a_k\times b_k
ak×bk”。
④ 那个这个以 a_k 和 b_k 作为竖边和横边的 “涂色块
” 一定能刚好塞满这个
n
×
m
n \times m
n×m 的表格。
比如说, n = 28 , m = 36 , k = 63 n=28,m=36,k=63 n=28,m=36,k=63。
k 的 “质因数对” 有:1和36、3和21、7和9。 其中 n 和 m 分别只能除得尽 7 和 9。
所以这个涂色块
的竖边长和横边长分别是 7 和 9。 然后按顺序一次塞涂色块
到表格中即可。
五、完整代码
● C 语言版本:
#include <stdio.h>
int a[1000010];
int main()
{
/* 输入模块 */
int T, n, m, k;
scanf("%d", &T);
while (T > 0)
{
T--;
/* 每一轮都要初始化 */
int cnt = 1;
int tim = 0;
int flag = 1;
/****************/
scanf("%d%d%d", &n, &m, &k);
if (n * m % k != 0)
{
printf("NO\n");
}
else
{
printf("YES\n");
/*********** 蛇形矩阵模块 **********/
for (int i = 1; i <= n; i++)
{
if (flag == 1) // 顺向蛇形处理
{
for (int j = 1; j <= m; j++)
{
tim++;
if (tim > k)
{
cnt++;
tim = 1;
}
a[j] = cnt; // 存储 “涂色数字”
}
flag = -flag; // 输完了这一行时, 蛇形准备转向
}
else
{
for (int j = m; j >= 1; j--) // 逆向蛇形处理
{
tim++;
if (tim > k)
{
cnt++;
tim = 1;
}
a[j] = cnt;
}
flag = -flag; // 输完了这一行时, 蛇形准备转向
}
/**************************/
/* 输出模块 */
for (int j = 1; j <= m; j++)
printf("%d ", a[j]);
printf("\n");
}
}
}
return 0;
}
● 运行结果:
● C++ 版本:和 C 的差不多,只是输入输出语法不太同。
六、参考附录
[1] 原题地址:https://www.luogu.com.cn/problem/P7886.
上一题链接: C/C++百题打卡[5/100]——合唱队形⭐️⭐️ 考查数组.
百题打卡总目录: 🚧 🚧 …
C/C++百题打卡[6/100]——表格涂色[题目源自 洛谷 ] ⭐️ ⭐️ ⭐️
标签:数组、洛谷月赛、Special Judge、2021
一周一更
2021/12/27