前言
一位大佬朋友给我投喂了一道很有趣的构造题,我开始并没有想到思路,初看题解时觉得很有意思。但细看时部分点被“显然”、“不难发现”创飞了半天才想明白。考虑到以往写题解的大佬直接跳过了部分对于我们这些蒟蒻来说的点,写此文记录一些我自己想了一会才明白的点,希望给后人一些启发。
题面
翻译一下
对于一个 n × n n \times n n×n 网格,用 ( r , c ) (r,c) (r,c) 表示从顶部数第 ( r + 1 ) (r+1) (r+1)行,从左侧数第 ( c + 1 ) (c+1) (c+1)列的正方形。使用 K K K 种颜色进行的"良好着色"是指满足以下条件的着色:
- 每个正方形被涂上了 K K K 种颜色中的一种。
- K K K 种颜色中的每一种都被用来涂了一些正方形。
- 让我们将 K K K 种颜色编号为 1,2,…,K。对于任何颜色 i i i 和 j j j ( 1 ≤ i ≤ K , 1 ≤ j ≤ K ) ( 1 \leq i \leq K, 1 \leq j \leq K) (1≤i≤K,1≤j≤K),涂有颜色 i i i 的每个正方形都有相同数量的相邻正方形涂有颜色 j j j。这里,与正方形 ( r , c ) (r,c) (r,c) 相邻的正方形是 ( ( r − 1 ) m o d n , c ) ( (r-1) \mod n, c) ((r−1)modn,c), ( ( r + 1 ) m o d n , c ) ( (r+1) \mod n, c) ((r+1)modn,c), ( r , ( c − 1 ) m o d n ) (r, (c-1) \mod n) (r,(c−1)modn)和 ( r , ( c + 1 ) m o d n ) (r, (c+1) \mod n) (r,(c+1)modn)(如果这些四个中同一个正方形出现多次,那么该正方形就被计数多次)。
给定 K K K,选择 n n n 在 1 和 500(含)之间的任意值,并构建一个 n × n n \times n n×n 网格的"良好着色"使用 K K K种颜色。这个问题的约束条件下,这总是可能的。
思路
考虑到 n n n 为1到500间的任意值,那当 k k k 比500小的时候构建 n × n n \times n n×n 可以直接每行一种颜色,构 k k k行 k k k列,相邻的对应颜色就都是 k k k。
当
k
k
k 更大时,就要改变思路。这里我思路卡死了。
通过尝试以及借鉴题解,对哦,可以斜着来!
为啥可以?因为所以格子的左和上是另一个颜色,右和下则又是一种不同于本身的颜色,且每个颜色的格子数量相同。
完成上面一步,还剩
k
−
500
k - 500
k−500 种颜色。而
k
k
k是小于1000的,我们可以把剩余颜色斜插和前面的颜色间隔出现。(如图为插入7这个颜色的示意图)
为啥可以嘞?因为我们只看上下左右的颜色,斜侧面一不一样不影响。
这样,我们就拿捏了这道题。当然,实现上还要用几个式子,请一步下一部分。
代码
#include <iostream>
using namespace std;
const int N=1010;
int k,a[N][N];
int main()
{
cin>>k;
if(k<=500)
{
cout<<k<<endl;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
cout<<i<<" ";
}
cout<<endl;
}
}
else
{
cout<<500<<endl;
for(int i=1;i<=500;i++)
{
for(int j=1;j<=500;j++)
{
a[i][j]=(i+j-2)%500+1;//观察可知i+j相等的格子颜色相同,进而计算可得此式
}
}
for(int i=501;i<=k;i++)
{
for(int j=1;j<=500;j+=2)//间隔改
{
a[(i-j+498)%500+1][j]=i;//从1开始间隔插
}
}
for(int i=1;i<=500;i++)
{
for(int j=1;j<=500;j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
return 0;
}
总结
——感谢另一位大佬朋友总结
花絮
本人和投喂给我的大佬交流应试教育对思维能力的毒害(大雾