2020牛客暑期多校训练营第六场Grid Coloring

Grid Coloring

原题请看这里

题目描述:

R o u n d g o d Roundgod Roundgod绘制了一个包含 n ∗ n n*n nn格子的图,他可以用 k k k种颜色,对每一条边进行染色,但有一些限制:

  1. 每种颜色必须出现相同次数
  2. 图上不能有单色环
  3. 每一行和每一列,至少包含 2 2 2种颜色。

输入描述:

输入包含多个测试用例。 输入的第一行包含一个整数 T T T ( ( ( 1 1 1 ≤ \le T T T ≤ \le 100 100 100 ) ) )在接下来的 T T T行中,每行包含两个整数 n n n k k k ( ( ( 1 1 1 ≤ \le n n n ≤ \le 200 200 200, 1 1 1 ≤ \le k k k ≤ \le 2 ( n + 1 ) n ) 2(n+1)n) 2(n+1)n),描述一个测试用例。

输出描述:

对于每个测试用例,如果没有解决方案,请输出 − 1 -1 1。否则,输出 2 ( n + 1 ) 2(n+1) 2(n+1)行。 对于前 n + 1 n+1 n+1行,每行包含 n n n个整数,表示每条水平线上的边缘颜色;对于后 n + 1 n+1 n+1行,每行包含 n n n个整数,表示每条垂直线上的边缘颜色。

样例输入:

2
2 3
2 5

样例输出:

1 2
3 1
3 2
1 3
2 1
2 3
-1

思路:

首先,我们可以排除三种无解的情况: k = 1 , n = 1 , 2 n ( n + 1 ) k=1,n=1,2n(n+1) k=1n=12n(n+1) m o d mod mod k ! = 0 k!=0 k!=0
然后我们就按照如下方式对图进行标号:
在这里插入图片描述
所以我们的标号方式是:自顶向下分别给边按照 1 1 1 n n n的顺序标号(如上图),然后我们将颜色 1 1 1 k k k按照顺序轮流放到这些边上。
1.对于每一个 1 ∗ 1 1*1 11的小环,两条纵边必定是相邻的序号,所以染的颜色必然不同
2.对于任意一个 a ( a + b ) , b > 0 a(a+b),b>0 a(a+b),b>0的环,横向边必定有相邻序号,所以染的颜色必然不同,由此又可以证明所有的横向边都是异色的
3.对于任意一个 ( a + b ) a , b > 0 (a+b)a,b>0 (a+b)a,b>0的环,如果他的横向边长为1,那么他就有相邻的纵向边,如果他的横向边 > 1 >1 >1那么他就有相邻横向边
所以任意一个环和横边均异色。
然后观察上图,发现:任意两条相邻纵向边的序号差必定为 2 n + 1 2n+1 2n+1
推理到这一步,我们只要证明任意两条相邻纵向边必定异色即可,即 g c d ( k , 2 n + 1 ) = 1 gcd(k,2n+1)=1 gcd(k,2n+1)=1,也就是 g c d ( 2 n ( n + 1 ) , 2 n + 1 ) = 1 gcd(2n(n+1),2n+1)=1 gcd(2n(n+1),2n+1)=1
证明:
g c d ( 2 n ( n + 1 ) , 2 n + 1 ) = 1 gcd(2n(n+1),2n+1)=1 gcd(2n(n+1),2n+1)=1
↔ \leftrightarrow g c d ( 2 n ( n + 1 ) − n ( 2 n + 1 ) , 2 n + 1 ) = 1 gcd(2n(n+1)-n(2n+1),2n+1)=1 gcd(2n(n+1)n(2n+1),2n+1)=1
↔ \leftrightarrow g c d ( n , 2 n + 1 − n ) = 1 gcd(n,2n+1-n)=1 gcd(n,2n+1n)=1 ↔ \leftrightarrow g c d ( n , n + 1 ) = 1 gcd(n,n+1)=1 gcd(n,n+1)=1
得证。
我还真不信如此复杂的推理得出的代码竟是如此简便…

A C AC AC C o d e Code Code

#include<bits/stdc++.h>
using namespace std;
const int MAXN=205;
int a[MAXN][MAXN],b[MAXN][MAXN],T,n,k,t;
int main(){
    scanf("%d",&T);
    while(T--){
    	t=0;
        scanf("%d%d",&n,&k);
        if(n==1|| k==1||(2*n*(n+1))%k){
            puts("-1");
            continue;
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
				t=t%k+1;
				a[i][j]=t;
			}
            for(int j=0;j<=n;j++){
				t=t%k+1;
				b[j][i]=t;
			}
        }
        for(int i=0;i<n;i++){
			t=t%k+1;
			a[n][i]=t;
		}
        for(int i=0;i<=n;i++){
            for(int j=0;j<n;j++)
                printf("%d ",a[i][j]);
            puts("");
        }
        for(int i=0;i<=n;i++){
            for(int j=0;j<n;j++)
                printf("%d ",b[i][j]);
            puts("");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值